From 3c54dd2631972b1025653a1fb39e674bfcbdc3aa Mon Sep 17 00:00:00 2001 From: yutiansut Date: Mon, 14 Jan 2019 20:10:56 +0800 Subject: [PATCH 1/5] #conda yam; --- conda.recipe/meta.yaml | 42 +++++++----------------------------------- 1 file changed, 7 insertions(+), 35 deletions(-) diff --git a/conda.recipe/meta.yaml b/conda.recipe/meta.yaml index dd06c8108..fdbb5237f 100644 --- a/conda.recipe/meta.yaml +++ b/conda.recipe/meta.yaml @@ -4,7 +4,8 @@ package: version: {{ data.get('version') }} source: - git_url: ../ +# git_url: ../ + path_url : ../QUANTAXIS build: number: 0 @@ -19,44 +20,15 @@ requirements: - setuptools run: - python - - setuptools - - pytz - - six - - nbformat >=4.4.0 - - clyent >=1.2.0 - - requests >=2.9.1 - - PyYAML >=3.12 - - python-dateutil >=2.6.1 - - pymongo - - bs4 - - pandas - - lxml - - matplotlib - - requests - - numpy>=1.12.0 - - pytesseract - - gevent-websocket>=0.10.1 - - apscheduler>=3.3.1 - - tornado - - zenlog - - pyecharts - - protobuf>=3.4 - - motor>=1.1 - - retrying - - seaborn>=0.8.1 - - selenium - - scrapy - - attrs>=17.4.0 - - pyconvert>=0.6.3 - - demjson>=2.2.4 -outputs: - - type: wheel - - name: {{ PKG_NAME }} about: home: {{ data.get('url') }} license: {{ data.get('license') }} license_family: MIT license_file: LICENSE - summary: {{ data.get('description') }} \ No newline at end of file + summary: {{ data.get('description') }} + +extra: + maintainers: + - yutiansut \ No newline at end of file From 7e86449c7cb7cc58f98d7778f7c94610d6811c76 Mon Sep 17 00:00:00 2001 From: yutiansut Date: Tue, 15 Jan 2019 00:50:16 +0800 Subject: [PATCH 2/5] #update --- QUANTAXIS/QAData/base_datastruct.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/QUANTAXIS/QAData/base_datastruct.py b/QUANTAXIS/QAData/base_datastruct.py index 9fbffac63..b2e1efa39 100644 --- a/QUANTAXIS/QAData/base_datastruct.py +++ b/QUANTAXIS/QAData/base_datastruct.py @@ -842,13 +842,10 @@ def new(self, data=None, dtype=None, if_fq=None): 🛠todo 没有这个?? inplace 是否是对于原类的修改 ?? """ data = self.data if data is None else data - #data.index= data.index.remove_unused_levels() dtype = self.type if dtype is None else dtype if_fq = self.if_fq if if_fq is None else if_fq - # 🛠todo 不是很理解这样做的意图, 已经copy了,还用data初始化 - # 🛠todo deepcopy 实现 ?还是 ? temp = copy(self) temp.__init__(data, dtype, if_fq) return temp From 206a333de2edbe7f0e9151a155a53f7edee9863f Mon Sep 17 00:00:00 2001 From: yutiansut Date: Tue, 15 Jan 2019 01:05:12 +0800 Subject: [PATCH 3/5] #update : move scrawly to split repo --- QUANTAXIS/__init__.py | 2 +- .../QUANTAXIS_SCRAPY_FETCH/__init__.py | 0 .../QUANTAXIS_SCRAPY_FETCH/items.py | 14 - .../QUANTAXIS_SCRAPY_FETCH/middlewares.py | 103 ------- .../QUANTAXIS_SCRAPY_FETCH/pipelines.py | 11 - .../QUANTAXIS_SCRAPY_FETCH/settings.py | 90 ------ .../spiders/__init__.py | 4 - .../spiders/eastmoney_zjlx.py | 40 --- .../eastmoney_simulation_web_trader.py | 110 ------- QUANTAXIS_CRAWLY/gecko_example.py | 39 --- .../jrj_divyield_simulation_web.py | 71 ----- QUANTAXIS_CRAWLY/jrj_simulation_web.py | 66 ----- QUANTAXIS_CRAWLY/readme.md | 13 - QUANTAXIS_CRAWLY/run_crawl.py | 23 -- QUANTAXIS_CRAWLY/run_selenium_alone.py | 272 ------------------ QUANTAXIS_CRAWLY/scrapy.cfg | 11 - .../eastmoney_simulation_web_trader_test.py | 10 - setup.py | 7 +- 18 files changed, 4 insertions(+), 882 deletions(-) delete mode 100644 QUANTAXIS_CRAWLY/QUANTAXIS_SCRAPY_FETCH/__init__.py delete mode 100644 QUANTAXIS_CRAWLY/QUANTAXIS_SCRAPY_FETCH/items.py delete mode 100644 QUANTAXIS_CRAWLY/QUANTAXIS_SCRAPY_FETCH/middlewares.py delete mode 100644 QUANTAXIS_CRAWLY/QUANTAXIS_SCRAPY_FETCH/pipelines.py delete mode 100644 QUANTAXIS_CRAWLY/QUANTAXIS_SCRAPY_FETCH/settings.py delete mode 100644 QUANTAXIS_CRAWLY/QUANTAXIS_SCRAPY_FETCH/spiders/__init__.py delete mode 100644 QUANTAXIS_CRAWLY/QUANTAXIS_SCRAPY_FETCH/spiders/eastmoney_zjlx.py delete mode 100644 QUANTAXIS_CRAWLY/eastmoney_simulation_web_trader.py delete mode 100644 QUANTAXIS_CRAWLY/gecko_example.py delete mode 100644 QUANTAXIS_CRAWLY/jrj_divyield_simulation_web.py delete mode 100644 QUANTAXIS_CRAWLY/jrj_simulation_web.py delete mode 100644 QUANTAXIS_CRAWLY/readme.md delete mode 100644 QUANTAXIS_CRAWLY/run_crawl.py delete mode 100644 QUANTAXIS_CRAWLY/run_selenium_alone.py delete mode 100644 QUANTAXIS_CRAWLY/scrapy.cfg delete mode 100644 QUANTAXIS_CRAWLY_TEST/eastmoney_simulation_web_trader_test.py diff --git a/QUANTAXIS/__init__.py b/QUANTAXIS/__init__.py index e374ccf88..4e2942f5c 100755 --- a/QUANTAXIS/__init__.py +++ b/QUANTAXIS/__init__.py @@ -31,7 +31,7 @@ 2017/4/8 """ -__version__ = '1.2.7.dev1' +__version__ = '1.2.7' __author__ = 'yutiansut' logo = ' \n \ ```````````````````````````````````````````````````````````````````````````````````````````````````````````````````````` \n \ diff --git a/QUANTAXIS_CRAWLY/QUANTAXIS_SCRAPY_FETCH/__init__.py b/QUANTAXIS_CRAWLY/QUANTAXIS_SCRAPY_FETCH/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/QUANTAXIS_CRAWLY/QUANTAXIS_SCRAPY_FETCH/items.py b/QUANTAXIS_CRAWLY/QUANTAXIS_SCRAPY_FETCH/items.py deleted file mode 100644 index 5060f9c26..000000000 --- a/QUANTAXIS_CRAWLY/QUANTAXIS_SCRAPY_FETCH/items.py +++ /dev/null @@ -1,14 +0,0 @@ -# -*- coding: utf-8 -*- - -# Define here the models for your scraped items -# -# See documentation in: -# https://doc.scrapy.org/en/latest/topics/items.html - -import scrapy - - -class QuantaxisScrapyFetchItem(scrapy.Item): - # define the fields for your item here like: - # name = scrapy.Field() - pass diff --git a/QUANTAXIS_CRAWLY/QUANTAXIS_SCRAPY_FETCH/middlewares.py b/QUANTAXIS_CRAWLY/QUANTAXIS_SCRAPY_FETCH/middlewares.py deleted file mode 100644 index 7d7d63076..000000000 --- a/QUANTAXIS_CRAWLY/QUANTAXIS_SCRAPY_FETCH/middlewares.py +++ /dev/null @@ -1,103 +0,0 @@ -# -*- coding: utf-8 -*- - -# Define here the models for your spider middleware -# -# See documentation in: -# https://doc.scrapy.org/en/latest/topics/spider-middleware.html - -from scrapy import signals - - -class QuantaxisScrapyFetchSpiderMiddleware(object): - # Not all methods need to be defined. If a method is not defined, - # scrapy acts as if the spider middleware does not modify the - # passed objects. - - @classmethod - def from_crawler(cls, crawler): - # This method is used by Scrapy to create your spiders. - s = cls() - crawler.signals.connect(s.spider_opened, signal=signals.spider_opened) - return s - - def process_spider_input(self, response, spider): - # Called for each response that goes through the spider - # middleware and into the spider. - - # Should return None or raise an exception. - return None - - def process_spider_output(self, response, result, spider): - # Called with the results returned from the Spider, after - # it has processed the response. - - # Must return an iterable of Request, dict or Item objects. - for i in result: - yield i - - def process_spider_exception(self, response, exception, spider): - # Called when a spider or process_spider_input() method - # (from other spider middleware) raises an exception. - - # Should return either None or an iterable of Response, dict - # or Item objects. - pass - - def process_start_requests(self, start_requests, spider): - # Called with the start requests of the spider, and works - # similarly to the process_spider_output() method, except - # that it doesn’t have a response associated. - - # Must return only requests (not items). - for r in start_requests: - yield r - - def spider_opened(self, spider): - spider.logger.info('Spider opened: %s' % spider.name) - - -class QuantaxisScrapyFetchDownloaderMiddleware(object): - # Not all methods need to be defined. If a method is not defined, - # scrapy acts as if the downloader middleware does not modify the - # passed objects. - - @classmethod - def from_crawler(cls, crawler): - # This method is used by Scrapy to create your spiders. - s = cls() - crawler.signals.connect(s.spider_opened, signal=signals.spider_opened) - return s - - def process_request(self, request, spider): - # Called for each request that goes through the downloader - # middleware. - - # Must either: - # - return None: continue processing this request - # - or return a Response object - # - or return a Request object - # - or raise IgnoreRequest: process_exception() methods of - # installed downloader middleware will be called - return None - - def process_response(self, request, response, spider): - # Called with the response returned from the downloader. - - # Must either; - # - return a Response object - # - return a Request object - # - or raise IgnoreRequest - return response - - def process_exception(self, request, exception, spider): - # Called when a download handler or a process_request() - # (from other downloader middleware) raises an exception. - - # Must either: - # - return None: continue processing this exception - # - return a Response object: stops process_exception() chain - # - return a Request object: stops process_exception() chain - pass - - def spider_opened(self, spider): - spider.logger.info('Spider opened: %s' % spider.name) diff --git a/QUANTAXIS_CRAWLY/QUANTAXIS_SCRAPY_FETCH/pipelines.py b/QUANTAXIS_CRAWLY/QUANTAXIS_SCRAPY_FETCH/pipelines.py deleted file mode 100644 index 8dcb57880..000000000 --- a/QUANTAXIS_CRAWLY/QUANTAXIS_SCRAPY_FETCH/pipelines.py +++ /dev/null @@ -1,11 +0,0 @@ -# -*- coding: utf-8 -*- - -# Define your item pipelines here -# -# Don't forget to add your pipeline to the ITEM_PIPELINES setting -# See: https://doc.scrapy.org/en/latest/topics/item-pipeline.html - - -class QuantaxisScrapyFetchPipeline(object): - def process_item(self, item, spider): - return item diff --git a/QUANTAXIS_CRAWLY/QUANTAXIS_SCRAPY_FETCH/settings.py b/QUANTAXIS_CRAWLY/QUANTAXIS_SCRAPY_FETCH/settings.py deleted file mode 100644 index 1263ba605..000000000 --- a/QUANTAXIS_CRAWLY/QUANTAXIS_SCRAPY_FETCH/settings.py +++ /dev/null @@ -1,90 +0,0 @@ -# -*- coding: utf-8 -*- - -# Scrapy settings for QUANTAXIS_SCRAPY_FETCH project -# -# For simplicity, this file contains only settings considered important or -# commonly used. You can find more settings consulting the documentation: -# -# https://doc.scrapy.org/en/latest/topics/settings.html -# https://doc.scrapy.org/en/latest/topics/downloader-middleware.html -# https://doc.scrapy.org/en/latest/topics/spider-middleware.html - -BOT_NAME = 'QUANTAXIS_SCRAPY_FETCH' - -SPIDER_MODULES = ['QUANTAXIS_SCRAPY_FETCH.spiders'] -NEWSPIDER_MODULE = 'QUANTAXIS_SCRAPY_FETCH.spiders' - - -# Crawl responsibly by identifying yourself (and your website) on the user-agent -#USER_AGENT = 'QUANTAXIS_SCRAPY_FETCH (+http://www.yourdomain.com)' - -# Obey robots.txt rules -ROBOTSTXT_OBEY = False - -# Configure maximum concurrent requests performed by Scrapy (default: 16) -CONCURRENT_REQUESTS = 32 - -# Configure a delay for requests for the same website (default: 0) -# See https://doc.scrapy.org/en/latest/topics/settings.html#download-delay -# See also autothrottle settings and docs -#DOWNLOAD_DELAY = 3 -# The download delay setting will honor only one of: -#CONCURRENT_REQUESTS_PER_DOMAIN = 16 -#CONCURRENT_REQUESTS_PER_IP = 16 - -# Disable cookies (enabled by default) -#COOKIES_ENABLED = False - -# Disable Telnet Console (enabled by default) -#TELNETCONSOLE_ENABLED = False - -# Override the default request headers: -DEFAULT_REQUEST_HEADERS = { - 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8', - 'Accept-Language': 'en', -} - -# Enable or disable spider middlewares -# See https://doc.scrapy.org/en/latest/topics/spider-middleware.html -#SPIDER_MIDDLEWARES = { -# 'QUANTAXIS_SCRAPY_FETCH.middlewares.QuantaxisScrapyFetchSpiderMiddleware': 543, -#} - -# Enable or disable downloader middlewares -# See https://doc.scrapy.org/en/latest/topics/downloader-middleware.html -#DOWNLOADER_MIDDLEWARES = { -# 'QUANTAXIS_SCRAPY_FETCH.middlewares.QuantaxisScrapyFetchDownloaderMiddleware': 543, -#} - -# Enable or disable extensions -# See https://doc.scrapy.org/en/latest/topics/extensions.html -#EXTENSIONS = { -# 'scrapy.extensions.telnet.TelnetConsole': None, -#} - -# Configure item pipelines -# See https://doc.scrapy.org/en/latest/topics/item-pipeline.html -#ITEM_PIPELINES = { -# 'QUANTAXIS_SCRAPY_FETCH.pipelines.QuantaxisScrapyFetchPipeline': 300, -#} - -# Enable and configure the AutoThrottle extension (disabled by default) -# See https://doc.scrapy.org/en/latest/topics/autothrottle.html -#AUTOTHROTTLE_ENABLED = True -# The initial download delay -#AUTOTHROTTLE_START_DELAY = 5 -# The maximum download delay to be set in case of high latencies -#AUTOTHROTTLE_MAX_DELAY = 60 -# The average number of requests Scrapy should be sending in parallel to -# each remote server -#AUTOTHROTTLE_TARGET_CONCURRENCY = 1.0 -# Enable showing throttling stats for every response received: -#AUTOTHROTTLE_DEBUG = False - -# Enable and configure HTTP caching (disabled by default) -# See https://doc.scrapy.org/en/latest/topics/downloader-middleware.html#httpcache-middleware-settings -#HTTPCACHE_ENABLED = True -#HTTPCACHE_EXPIRATION_SECS = 0 -#HTTPCACHE_DIR = 'httpcache' -#HTTPCACHE_IGNORE_HTTP_CODES = [] -#HTTPCACHE_STORAGE = 'scrapy.extensions.httpcache.FilesystemCacheStorage' diff --git a/QUANTAXIS_CRAWLY/QUANTAXIS_SCRAPY_FETCH/spiders/__init__.py b/QUANTAXIS_CRAWLY/QUANTAXIS_SCRAPY_FETCH/spiders/__init__.py deleted file mode 100644 index ebd689ac5..000000000 --- a/QUANTAXIS_CRAWLY/QUANTAXIS_SCRAPY_FETCH/spiders/__init__.py +++ /dev/null @@ -1,4 +0,0 @@ -# This package will contain the spiders of your Scrapy project -# -# Please refer to the documentation for information on how to create and manage -# your spiders. diff --git a/QUANTAXIS_CRAWLY/QUANTAXIS_SCRAPY_FETCH/spiders/eastmoney_zjlx.py b/QUANTAXIS_CRAWLY/QUANTAXIS_SCRAPY_FETCH/spiders/eastmoney_zjlx.py deleted file mode 100644 index 8cea679bc..000000000 --- a/QUANTAXIS_CRAWLY/QUANTAXIS_SCRAPY_FETCH/spiders/eastmoney_zjlx.py +++ /dev/null @@ -1,40 +0,0 @@ -''' - -Author 604829050@qq.com -https://blog.csdn.net/elecjack/article/details/51532482 -''' - -import scrapy - -from selenium import webdriver -from selenium.webdriver.support.ui import WebDriverWait -#from buluo.items import BuluoItem - - - -class MySpiderForEastMoney(scrapy.Spider): - name = 'zjlx' - #start_urls = ['http://data.eastmoney.com/zjlx/detail.html'] - - def __init__(self): - super(MySpiderForEastMoney, self).__init__() - - #设定chromedriver 使用相对路径 - self.driver = webdriver.Chrome('./thirdpart/chromedriver') - - #启动chrome - self.driver.set_page_load_timeout(15) # throw a TimeoutException when thepage load time is more than 15 seconds - self.driver.minimize_window() - - def start_requests(self): - urls = ['http://data.eastmoney.com/zjlx/002433.html'] - for url in urls: - yield scrapy.Request(url=url, callback=self.parse) - - def parse(self, response): - filename = 'zjlx.html' - - - def closed(self): - #结束chrome - self.driver.close() diff --git a/QUANTAXIS_CRAWLY/eastmoney_simulation_web_trader.py b/QUANTAXIS_CRAWLY/eastmoney_simulation_web_trader.py deleted file mode 100644 index 556ea0664..000000000 --- a/QUANTAXIS_CRAWLY/eastmoney_simulation_web_trader.py +++ /dev/null @@ -1,110 +0,0 @@ -''' - -''' -import time -import re -from selenium import webdriver -import sys -from selenium.common.exceptions import NoSuchElementException -import sqlite3 - -class SingletonMeta(type): - def __init__(cls, name, bases, namespaces): - super().__init__(cls, name, bases, namespaces) - cls.instance = None - - def __call__(cls, *args, **kwargs): - if cls.instance is None: - cls.instance = super().__call__(*args, **kwargs) - else: - print("instance already existed!") - return cls.instance - - - -class EastMoneySimulationWebTrader(): - - - def startTrade(self): - - urls = 'http://www.eastmoney.com/' #登陆到我的东方财富 - pa = re.compile(r'\w+') - - self.webdriver_parent_path = './QUANTAXIS_WEBDRIVER/macos/' - - if sys.platform == 'darwin': - browser = webdriver.Chrome(self.webdriver_parent_path+'chromedriver') - elif sys.platform == 'win32': - browser = webdriver.Chrome(self.webdriver_parent_path+'chromedriver') - elif sys.platform == 'linux': - browser = webdriver.Chrome(self.webdriver_parent_path+'chromedriver') - # todo 🛠 linux 下没有测试, linux 下 非gui环境下,用chrome headless driver - print("🎃") - print("🎃./selenium_driver/linux/chromedrive linux 平台上的的 🤖chromedriver 的路径") - print("🎃./selenium_driver/windows/chromedrive windows 平台上的的 🤖chromedriver 的路径") - print("🎃 https://npm.taobao.org/mirrors/chromedriver/ 🤖chromedriver下载地址") - print("🎃") - return - - # 启动chrome - print("🖼 准备获取数据, 打开chromedrive ,") - browser.set_page_load_timeout(30) # throw a TimeoutException when thepage load time is more than 15 seconds - #browser.minimize_window() - - print("🖼 正在请求数据中,请耐心等待 🍺 ⌛ ⌛ ⌛ ⌛ ⌛ ️") - #.get(urls) - #browser. - browser.get(urls) - - num = browser.window_handles - - print(type(num[0])) - - - browser.find_element_by_id('loginMenu').click() - - num = browser.window_handles - # browser.switch_to(num[1]) - time.sleep(1) # Let the page load - time.sleep(1) # Let the page load - - #spanTag = browser.find_elements_by_name('body') - - #browser.find_elements_by_id() - - #currHandle = browser.current_window_handler - browser.switch_to.window(num[1]) - - txt = browser.find_element_by_xpath('/html/body/div[1]/div/div/h1') - print(txt.text) - - frameLogIn = browser.find_element_by_id('frame_login') - browser.switch_to.frame(frameLogIn) - - - #account = browser.find_element_by_id('txt_account') - account = browser.find_elements_by_xpath('//*[@id="txt_account"]') - - #输入用户名 - account[0].send_keys('*********') - #输入密码 - password = browser.find_element_by_id('txt_pwd') - password.send_keys('*********') - - browser.find_element_by_id('btn_login').click() - # id; txt_account - # account; txt_pwd - - - time.sleep(1) # Let the page load - time.sleep(1) # Let the page load - time.sleep(1) # Let the page load - time.sleep(1) # Let the page load - time.sleep(1) # Let the page load - - - # 成功登陆东方财富 - - browser.quit() - -pass diff --git a/QUANTAXIS_CRAWLY/gecko_example.py b/QUANTAXIS_CRAWLY/gecko_example.py deleted file mode 100644 index b3517dafd..000000000 --- a/QUANTAXIS_CRAWLY/gecko_example.py +++ /dev/null @@ -1,39 +0,0 @@ -import time - -import pandas as pd -from selenium import webdriver - -"""这里我给了一个同花顺的页面爬虫 用于gecko_driver 也就是 火狐浏览器内核爬虫的教学 - -推荐使用火狐浏览器的内核 配置方便 -""" - -opener = webdriver.Firefox() # should make sure the gekkodriver.exe in path -data = [] - - -for item in ['gn', 'dy', 'thshy', 'zjhhy']: - opener.get('http://q.10jqka.com.cn/{}/'.format(item)) - - hpage = opener.page_source - - # opener.save_screenshot('page_gn.png') - try: - if opener.find_element_by_class_name('cate_toggle.boxShadow').text == '收起': - pass - else: - opener.find_element_by_class_name('cate_toggle.boxShadow').click() - except: - pass - - res = opener.find_elements_by_xpath('/html/body/div/div/div/div/div/a') - - data.extend([[res.text, res.get_attribute('href'), item] for res in res]) - - time.sleep(1) - - -res = pd.DataFrame(data) -print(res) -opener.close() -res.to_csv('ths.csv') diff --git a/QUANTAXIS_CRAWLY/jrj_divyield_simulation_web.py b/QUANTAXIS_CRAWLY/jrj_divyield_simulation_web.py deleted file mode 100644 index 200fb8292..000000000 --- a/QUANTAXIS_CRAWLY/jrj_divyield_simulation_web.py +++ /dev/null @@ -1,71 +0,0 @@ -''' - -''' -import pandas as pd -from selenium import webdriver -from bs4 import BeautifulSoup -import demjson -from QUANTAXIS_CRAWLY.run_selenium_alone import * -from QUANTAXIS.QAUtil import (QA_util_getBetweenQuarter,QA_util_add_months, - QA_util_today_str,QA_util_datetime_to_strdate) - -def get_headers(report_date,headers): - url = 'http://stock.jrj.com.cn/report/szph.shtml?p=1&ob=11&od=d&_ed={}'.format(report_date) - headers.update({"Referer":url}) - options = webdriver.ChromeOptions() - # 设置中文 - for (key,value) in headers.items(): - options.add_argument('%s="%s"' % (key, value)) - driver = webdriver.Chrome(chrome_options=options) - driver.get(url) - cookies=driver.get_cookies() - driver.quit() - headers.update({"Cookies":cookies}) - return(headers) - -def read_stock_divyield(report_date, headers = None, page=1): - if headers == None: - headers = {'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8', - 'Accept-Language': 'zh-CN,zh;q=0.9', - 'Cache-Control': 'max-age=0', - 'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/48.0.2564.116 Safari/537.36', - 'Connection': 'keep-alive' - } - args= {"report_date": report_date, "unixstamp": int(round(time.time() * 1000))} - - strUrl1 = "http://stock.jrj.com.cn/report/js/sz/{report_date}.js?ts={unixstamp}".format(**args) - if page == 1: - headers = get_headers(report_date,headers) - options = webdriver.ChromeOptions() - for (key,value) in headers.items(): - options.add_argument('%s="%s"' % (key, value)) - - driver = webdriver.Chrome(chrome_options=options) - driver.get(strUrl1) - soup = BeautifulSoup(driver.page_source, "html.parser").body.text - driver.quit() - start_str = 'var fhps = '.format(**args) - res = demjson.decode(soup.strip(start_str).strip(';').replace(''', -, -,''',',0,0,').replace(''', -,''',',0,')) - data = pd.DataFrame(res['data']) - if data.shape[0] > 0: - page_num = res['summary']['total'] - data=data.drop_duplicates(keep='first') - data.columns= ['a_stockcode','a_stocksname','div_info','div_type_code','bonus_shr', - 'cash_bt','cap_shr','epsp','ps_cr','ps_up','reg_date','dir_dcl_date', - 'a_stockcode1','ex_divi_date','prg'] - data['report_date']=report_date - data['crawl_date']=QA_util_today_str() - return(data, page_num) - else: - print("No divyield data for today") - return(None,None) - - -def get_stock_divyield(report_date, headers = None, page=1): - data, page_num = read_stock_divyield(report_date, headers, page) - if data is None: - data = pd.DataFrame() - return(data) \ No newline at end of file diff --git a/QUANTAXIS_CRAWLY/jrj_simulation_web.py b/QUANTAXIS_CRAWLY/jrj_simulation_web.py deleted file mode 100644 index d40a5dfcb..000000000 --- a/QUANTAXIS_CRAWLY/jrj_simulation_web.py +++ /dev/null @@ -1,66 +0,0 @@ -''' - -''' -import pandas as pd -from selenium import webdriver -from bs4 import BeautifulSoup -import demjson -from QUANTAXIS_CRAWLY.run_selenium_alone import * -from QUANTAXIS.QAUtil import (QA_util_getBetweenQuarter,QA_util_add_months, - QA_util_today_str,QA_util_datetime_to_strdate) - -def get_headers(report_date,headers): - url = 'http://stock.jrj.com.cn/report/plsj.shtml?ob=2&od=d&_td=&_pid={}'.format(report_date) - headers.update({"Referer":url}) - options = webdriver.ChromeOptions() - # 设置中文 - for (key,value) in headers.items(): - options.add_argument('%s="%s"' % (key, value)) - driver = webdriver.Chrome(chrome_options=options) - driver.get(url) - cookies=driver.get_cookies() - driver.quit() - headers.update({"Cookies":cookies}) - return(headers) - -def read_financial_report_date(report_date, headers = None, psize= 2000,vname="plsj",page=1): - if headers == None: - headers = {'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8', - 'Accept-Language': 'zh-CN,zh;q=0.9', - 'Cache-Control': 'max-age=0', - 'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/48.0.2564.116 Safari/537.36', - 'Connection': 'keep-alive' - } - args= {"report_date": report_date, "psize": psize, "vname": vname, 'page': page} - - strUrl1 = "http://app.jrj.com.cn/jds/data_ylj.php?cid=1002&_pd=&_pd2=&_pid={report_date}&ob=2&od=d&page={page}&psize={psize}&vname={vname}".format(**args) - if page == 1: - headers = get_headers(report_date,headers) - options = webdriver.ChromeOptions() - for (key,value) in headers.items(): - options.add_argument('%s="%s"' % (key, value)) - - driver = webdriver.Chrome(chrome_options=options) - driver.get(strUrl1) - soup = BeautifulSoup(driver.page_source, "html.parser").body.text - driver.quit() - start_str = 'var {vname} = '.format(**args) - res = demjson.decode(soup.strip(start_str).strip(';')) - pages = args['page'] - data = pd.DataFrame(res['data']) - page_num = res['summary']['pages'] - - - while pages < page_num: - pages = pages + 1 - res, page_num = read_financial_report_date(report_date,headers,page = pages) - data = data.append(res) - data=data.drop_duplicates(keep='first') - return(data, page_num) - -def get_financial_report_date(report_date, headers = None, psize= 2000,vname="plsj",page=1): - data, page_num = read_financial_report_date(report_date, headers, psize,vname,page) - data.columns= ['code','name','pre_date','first_date','second_date','third_date','real_date','codes'] - data['report_date']=report_date - data['crawl_date']=QA_util_today_str() - return(data[data["real_date"].apply(lambda x: len(x)!=0)]) \ No newline at end of file diff --git a/QUANTAXIS_CRAWLY/readme.md b/QUANTAXIS_CRAWLY/readme.md deleted file mode 100644 index 76b078e76..000000000 --- a/QUANTAXIS_CRAWLY/readme.md +++ /dev/null @@ -1,13 +0,0 @@ -pip install selenium - -download the chromedriver -https://npm.taobao.org/mirrors/chromedriver/ - -please download the version 2.39 and upgrade your chrome browser to the match version. - -if version does not match, you will see the error message like below. -selenium.common.exceptions.SessionNotCreatedException: Message: session not created exception: Chrome version must be >= 66.0.3359.0 - (Driver info: chromedriver=2.39.562713 (dd642283e958a93ebf6891600db055f1f1b4f3b2),platform=Mac OS X 10.13.5 x86_64) - - -采用相对路径: diff --git a/QUANTAXIS_CRAWLY/run_crawl.py b/QUANTAXIS_CRAWLY/run_crawl.py deleted file mode 100644 index f4972bd74..000000000 --- a/QUANTAXIS_CRAWLY/run_crawl.py +++ /dev/null @@ -1,23 +0,0 @@ -# -#from scrapy import project, signals - - -#import scrapy -''' -copy the from scrapy from the environment -just for easy run by IDE for debug purpose! - -''' -import re -import sys - -from scrapy.cmdline import execute - - -if __name__ == '__main__': - - sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0]) - sys.argv.append('crawl') - sys.argv.append('zjlx') - - sys.exit(execute()) \ No newline at end of file diff --git a/QUANTAXIS_CRAWLY/run_selenium_alone.py b/QUANTAXIS_CRAWLY/run_selenium_alone.py deleted file mode 100644 index 7834a4409..000000000 --- a/QUANTAXIS_CRAWLY/run_selenium_alone.py +++ /dev/null @@ -1,272 +0,0 @@ -import scrapy - -import time -import re -from selenium import webdriver -import sys -from selenium.webdriver.common.keys import Keys -from selenium.webdriver.common.action_chains import ActionChains -from selenium.common.exceptions import NoSuchElementException - -import sqlite3 -import pandas as pd -import time -import timeit - - -from QUANTAXIS.QAUtil import (DATABASE) - -def open_chrome_driver(): - - - if sys.platform == 'darwin': - browser = webdriver.Chrome('./QUANTAXIS_WEBDRIVER/macos/chromedriver') - elif sys.platform == 'win32': - browser = webdriver.Chrome('./QUANTAXIS_WEBDRIVER/windows/chromedriver') - elif sys.platform == 'linux': - browser = webdriver.Chrome('./QUANTAXIS_WEBDRIVER/linux/chromedriver') - # todo 🛠 linux 下没有测试, linux 下 非gui环境下,用chrome headless driver - print("🎃") - print("🎃./selenium_driver/linux/chromedrive linux 平台上的的 🤖chromedriver 的路径") - print("🎃./selenium_driver/windows/chromedrive windows 平台上的的 🤖chromedriver 的路径") - print("🎃 https://npm.taobao.org/mirrors/chromedriver/ 🤖chromedriver下载地址") - print("🎃") - return browser - -def close_chrome_dirver(browser): - browser.quit() - - - - - -def read_east_money_page_zjlx_to_sqllite(stockCode, browser): - - urls = 'http://data.eastmoney.com/zjlx/{}.html'.format(stockCode) - pa=re.compile(r'\w+') - - # 启动chrome - print("🖼 准备获取数据, 打开chromedrive ,") - browser.set_page_load_timeout(10) # throw a TimeoutException when thepage load time is more than 15 seconds - #browser.minimize_window() - - print("🖼 正在请求数据中,请耐心等待 🍺 ⌛ ⌛ ⌛ ⌛ ⌛ ️") - - browser.get(urls) - #time.sleep(1) # Let the page load - - try: - #result = [] - zjlxtable = browser.find_element_by_id('content_zjlxtable') - table_elements = zjlxtable.find_element_by_tag_name('table') - - table_header = table_elements.find_elements_by_tag_name('thead') - # todo 🛠 不知道为何,tbody 标签那不到数据 - table_body = table_elements.find_elements_by_tag_name('tbody') - - #chrome debug copy xpath - table_body2 = browser.find_elements_by_xpath('//*[@id="dt_1"]/tbody') - - head1_list = [] - head2_list = [] - - if isinstance(table_header,list) == True: - #print(table_header[0]) - #print(table_header[0].text) - - table_header_row = table_header[0].find_elements_by_tag_name('tr') - - assert(len(table_header_row) == 2) - - table_head_name1 = table_header_row[0].find_elements_by_tag_name('th') - table_head_name2 = table_header_row[1].find_elements_by_tag_name('th') - - for i in range(len(table_head_name1)): - head_name = table_head_name1[i].get_attribute("innerHTML") - head1_list.append(head_name) - #print(table_head_name1[i].get_attribute("value")) - - for i in range(len(table_head_name2)): - head_name = table_head_name2[i].get_attribute("innerHTML") - head2_list.append(head_name) - #print(table_head_name1[i].get_attribute("value")) - else: - #raise NoSuchElementException - print("error !!!!!!!!") - - - row1_list = [] - if isinstance(table_body2,list) == True: - - table_body_row = table_body2[0].find_elements_by_tag_name('tr') - print("🖼 成功获取 %d 天的资金流向数据️"%(len(table_body_row))) - - t0 = time.clock() - - row_length = len(table_body_row) - for i in range(row_length): - - - table_body_cell = table_body_row[i].find_elements_by_tag_name('td') - assert( len(table_body_cell) == 13 ) - - - - dict_row = {} - dict_row['stock_code'] = stockCode - - dict_row['date'] = table_body_cell[0].text - dict_row['zljll_je_wy'] = table_body_cell[1].text - dict_row['zljll_jzb_bfb'] = table_body_cell[2].text - dict_row['cddjll_je_wy'] = table_body_cell[3].text - dict_row['cddjll_je_jzb'] = table_body_cell[4].text - dict_row['ddjll_je_wy'] = table_body_cell[5].text - dict_row['ddjll_je_jzb'] = table_body_cell[6].text - dict_row['zdjll_je_wy'] = table_body_cell[7].text - dict_row['zdjll_je_jzb'] = table_body_cell[8].text - dict_row['xdjll_je_wy'] = table_body_cell[9].text - dict_row['xdjll_je_jzb'] = table_body_cell[10].text - dict_row['close_price'] = table_body_cell[11].text - dict_row['change_price'] = table_body_cell[12].text - - row1_list.append(dict_row) - - - - # todo 🛠 循环获取网页速度非常慢, 进一步学习 selenium 的操作, 批量一次获取数据 - iPct = round((i / row_length) * 100.0) - s1 = "\r读取数据%d%%[%s%s]" % (iPct, "🐢" * iPct, " " * (100 - iPct)) - sys.stdout.write(s1) - sys.stdout.flush() - - # v = [] - # v.append() # 日期 - # v.append(table_body_cell[1].text) # 收盘价 - # v.append(table_body_cell[2].text) # 涨跌幅 - # v.append(table_body_cell[3].text) # 主力净流入_净额(万元) - # v.append(table_body_cell[4].text) # 主力净流入_净占比(%) - # v.append(table_body_cell[5].text) # 超大单净流入_净额(万元) - # v.append(table_body_cell[6].text) # 超大单净流入_净占比(%) - # v.append(table_body_cell[7].text) # 大单净流入_净额(万元) - # v.append(table_body_cell[8].text) # 大单净流入_净占比(%) - # v.append(table_body_cell[9].text) # 中单净流入_净额(万元) - # v.append(table_body_cell[10].text)# 中单净流入_净占比(%) - # v.append(table_body_cell[11].text)# 小单净流入_净额(万元) - # v.append(table_body_cell[12].text)# 小单净流入_净占比(%) - - t = time.clock() - t0 - print('总体耗时间: %f'%t) - - else: - #raise NoSuchElementException - print("error !!!!!!!!") - - - assert (len(row1_list) != 0 ) - assert (len(head1_list) != 0) - assert (len(head2_list) != 0) - - ActionChains(browser).key_down(Keys.CONTROL).send_keys("w").key_up(Keys.CONTROL).perform() - - print("🖼 完成获取数据,关闭chromedrive ,") - - df = pd.DataFrame(row1_list) - - # print(df) - - client = DATABASE - coll_stock_zjlx = client.eastmoney_stock_zjlx - - # coll_stock_zjlx.insert_many(QA_util_to_json_from_pandas(df)) - - print("🥕准备写入mongodb 🎞保存数据库 ", 'eastmoney_stock_zjlx' ) - - new_rec = 0 - for i in range(len(row1_list)): - aRec = row1_list[i] - - # 🛠todo 当天结束后,获取当天的资金流相,当天的资金流向是瞬时间点的 - ret = coll_stock_zjlx.find_one(aRec) - if ret == None: - coll_stock_zjlx.insert_one(aRec) - new_rec = new_rec + 1 - #print("🤑 插入新的记录 ", aRec) - else: - #print("😵 记录已经存在 ", ret) - pass - - print("🖼 🎞写入数据库 🐌 新纪录 ", new_rec, "条 💹 ") - #保存sqllite文件 - #print("🥕准备写入数据库文件 🎞保存路径",save_sqlite_full_path_name) - - # conn = sqlite3.connect(save_sqlite_full_path_name) - # # Create table - # conn.execute('''CREATE TABLE IF NOT EXISTS - # zjlx(code text, date text, - # close text, chg text, - # zljll_je text, zljll_jzb text, - # cddjll_je text, cddjll_jzb text, - # ddjll_je text, ddjll_jzb text, - # zdjll_je text, zdjll_jzb text, - # xdjll_je text, xdjll_jzb text, - # primary key(code,date)) - # ''') - # - # for a_row in row1_list: - # # 如果记录重复,则替换 - # strSQLExec = 'INSERT OR REPLACE INTO zjlx(code, date, close, chg, \ - # zljll_je, zljll_jzb, \ - # cddjll_je, cddjll_jzb, \ - # ddjll_je, ddjll_jzb, \ - # zdjll_je, zdjll_jzb, \ - # xdjll_je, xdjll_jzb) \ - # VALUES("%s","%s","%s","%s",\ - # "%s","%s",\ - # "%s","%s",\ - # "%s","%s",\ - # "%s","%s",\ - # "%s","%s")'%\ - # (stockCode, - # a_row[0], - # a_row[1], - # a_row[2], - # a_row[3], - # a_row[4], - # a_row[5], - # a_row[6], - # a_row[7], - # a_row[8], - # a_row[9], - # a_row[10], - # a_row[11], - # a_row[12] - # ) - # - # conn.execute(strSQLExec) - # - # print("🖼 🎞写入数据库 🐌", a_row, " 💹 ") - - # conn.commit() - # - # conn.close() - - - except NoSuchElementException: - print("❌ read_east_money_page_zjlx_to_sqllite 读取网页数据错误 🤮") - - #driver.close() - -#todo 🛠 添加金融界 -#todo 🛠 添加同花顺 - - - - -if __name__ == '__main__': - - # code = '300439' - # read_east_money_page_zjlx_to_sqllite(stockCode= code, save_sqlite_full_path_name="./300439_test.sqlite.db") - # - # code = '002344' - # read_east_money_page_zjlx_to_sqllite(stockCode =code, save_sqlite_full_path_name="./002433_test.sqlite.db") - pass \ No newline at end of file diff --git a/QUANTAXIS_CRAWLY/scrapy.cfg b/QUANTAXIS_CRAWLY/scrapy.cfg deleted file mode 100644 index 14fdf74b9..000000000 --- a/QUANTAXIS_CRAWLY/scrapy.cfg +++ /dev/null @@ -1,11 +0,0 @@ -# Automatically created by: scrapy startproject -# -# For more information about the [deploy] section see: -# https://scrapyd.readthedocs.io/en/latest/deploy.html - -[settings] -default = QUANTAXIS_SCRAPY_FETCH.settings - -[deploy] -#url = http://localhost:6800/ -project = QUANTAXIS_SCRAPY_FETCH diff --git a/QUANTAXIS_CRAWLY_TEST/eastmoney_simulation_web_trader_test.py b/QUANTAXIS_CRAWLY_TEST/eastmoney_simulation_web_trader_test.py deleted file mode 100644 index c8bb8abe8..000000000 --- a/QUANTAXIS_CRAWLY_TEST/eastmoney_simulation_web_trader_test.py +++ /dev/null @@ -1,10 +0,0 @@ -from QUANTAXIS_CRAWLY.eastmoney_simulation_web_trader import EastMoneySimulationWebTrader -import unittest - -class TestEastMoneySimTrader(unittest.TestCase): - - def testTrader(self): - EMSimTrader = EastMoneySimulationWebTrader() - EMSimTrader.startTrade() - - diff --git a/setup.py b/setup.py index e5e4cd5ca..6c04b0d96 100644 --- a/setup.py +++ b/setup.py @@ -67,7 +67,7 @@ def read(fname): """ PACKAGES = ["QUANTAXIS", "QUANTAXIS.QAFetch", "QUANTAXIS.QACmd", "QUANTAXIS.QAMarket", 'QUANTAXIS.QASetting',"QUANTAXIS.QACmd", "QUANTAXIS.QAApplication", "QUANTAXIS.QAEngine", "QUANTAXIS.QAData", 'QUANTAXIS.QAData.proto', "QUANTAXIS.QAAnalysis", 'QUANTAXIS.QASelector', - "QUANTAXIS.QASU", "QUANTAXIS.QAUtil", "QUANTAXIS.QAARP", "QUANTAXIS.QAIndicator", "QUANTAXIS_CRAWLY"] + "QUANTAXIS.QASU", "QUANTAXIS.QAUtil", "QUANTAXIS.QAARP", "QUANTAXIS.QAIndicator"] """ """ @@ -105,9 +105,8 @@ def read(fname): 'Operating System :: OS Independent', ], install_requires=['pandas>=0.23.4', 'numpy>=1.12.0', 'tushare', 'flask_socketio>=2.9.0 ', 'motor>=1.1', 'seaborn>=0.8.1', 'pyconvert>=0.6.3', - 'lxml>=4.0', ' beautifulsoup4', 'matplotlib', 'requests', 'selenium', 'tornado', - 'demjson>=2.2.4', 'scrapy', - 'pymongo>=3.7', 'six>=1.10.0', 'tabulate>=0.7.7', 'pytdx>=1.67', 'retrying>=1.3.3', + 'lxml>=4.0', ' beautifulsoup4', 'matplotlib', 'requests', 'tornado', + 'demjson>=2.2.4', 'pymongo>=3.7', 'six>=1.10.0', 'tabulate>=0.7.7', 'pytdx>=1.67', 'retrying>=1.3.3', 'zenlog>=1.1', 'delegator.py>=0.0.12', 'flask>=0.12.2', 'pyecharts', 'protobuf>=3.4.0'], entry_points={ 'console_scripts': [ From 47277f73fa7ba35907e7d430f9dbf6c97731f6fc Mon Sep 17 00:00:00 2001 From: yutiansut Date: Tue, 15 Jan 2019 02:44:03 +0800 Subject: [PATCH 4/5] #update --- QUANTAXIS/QAFetch/QAcalendar.py | 6 - QUANTAXIS/QAFetch/QAdivyield.py | 6 - QUANTAXIS/QASU/crawl_eastmoney.py | 238 ------------------ .../QASU/crawl_jrj_financial_reportdate.py | 92 ------- QUANTAXIS/QASU/crawl_jrj_stock_divyield.py | 92 ------- QUANTAXIS/QASU/main.py | 6 +- .../QASU/save_to_db_fields_description.py | 100 -------- 7 files changed, 3 insertions(+), 537 deletions(-) delete mode 100644 QUANTAXIS/QAFetch/QAcalendar.py delete mode 100644 QUANTAXIS/QAFetch/QAdivyield.py delete mode 100644 QUANTAXIS/QASU/crawl_eastmoney.py delete mode 100644 QUANTAXIS/QASU/crawl_jrj_financial_reportdate.py delete mode 100644 QUANTAXIS/QASU/crawl_jrj_stock_divyield.py delete mode 100644 QUANTAXIS/QASU/save_to_db_fields_description.py diff --git a/QUANTAXIS/QAFetch/QAcalendar.py b/QUANTAXIS/QAFetch/QAcalendar.py deleted file mode 100644 index 3116a52f2..000000000 --- a/QUANTAXIS/QAFetch/QAcalendar.py +++ /dev/null @@ -1,6 +0,0 @@ - -from QUANTAXIS_CRAWLY.jrj_simulation_web import get_financial_report_date - -def QA_fetch_get_financial_calendar(report_date): - data = get_financial_report_date(report_date) - return(data) diff --git a/QUANTAXIS/QAFetch/QAdivyield.py b/QUANTAXIS/QAFetch/QAdivyield.py deleted file mode 100644 index 5f6cd1caa..000000000 --- a/QUANTAXIS/QAFetch/QAdivyield.py +++ /dev/null @@ -1,6 +0,0 @@ - -from QUANTAXIS_CRAWLY.jrj_divyield_simulation_web import get_stock_divyield - -def QA_fetch_get_stock_divyield(report_date): - data = get_stock_divyield(report_date) - return(data) diff --git a/QUANTAXIS/QASU/crawl_eastmoney.py b/QUANTAXIS/QASU/crawl_eastmoney.py deleted file mode 100644 index 46da92935..000000000 --- a/QUANTAXIS/QASU/crawl_eastmoney.py +++ /dev/null @@ -1,238 +0,0 @@ -import os -from QUANTAXIS.QASetting import QALocalize -#from QUANTAXIS_CRAWLY.run_selenium_alone import (read_east_money_page_zjlx_to_sqllite, open_chrome_driver, close_chrome_dirver) -from QUANTAXIS_CRAWLY.run_selenium_alone import * -import urllib -import pandas as pd -import time - -from QUANTAXIS.QAUtil import (DATABASE) - - - -def QA_request_eastmoney_zjlx( param_stock_code_list ): - # 改用 - strUrl = "http://data.eastmoney.com/zjlx/{}.html".format(param_stock_code_list[0]) - - # 延时 - time.sleep(1.223) - - response = urllib.request.urlopen(strUrl) - content = response.read() - - # 🛠todo 改用 re 正则表达式做匹配 - strings = content.decode("utf-8", "ignore") - string_lines = strings.split("\r\n") - - values = [] - for aline in string_lines: - aline = aline.strip() - if 'EM_CapitalFlowInterface' in aline: - aline = aline.strip() - if aline.startswith('var strUrl = '): - if 'var strUrl = ' in aline: - aline = aline[len('var strUrl = '):] - values = aline.split('+') - - break - - print(values) - - for iStockCode in range(len(param_stock_code_list)): - requestStr = "" - - strCode = param_stock_code_list[iStockCode] - if strCode[0:2] == '60': - _stockMarke = '1' - elif strCode[0:2] == '00' or strCode[0:2] == '30': - _stockMarke = '2' - else: - print(strCode + " 暂不支持, 60, 00, 30 开头的股票代码") - return - - for iItem in values: - if '_stockCode' in iItem: - requestStr = requestStr + param_stock_code_list[iStockCode] - elif '_stockMarke' in iItem: - requestStr = requestStr + _stockMarke - else: - if 'http://ff.eastmoney.com/' in iItem: - requestStr = 'http://ff.eastmoney.com/' - else: - iItem = iItem.strip(' "') - iItem = iItem.rstrip(' "') - requestStr = requestStr + iItem - - # 延时 - time.sleep(1.456) - - response = urllib.request.urlopen(requestStr) - content2 = response.read() - - strings = content2.decode("utf-8", "ignore") - - list_data_zjlx = [] - - if 'var aff_data=({data:[["' in strings: - leftChars = strings[len('var aff_data=({data:[["'):] - dataArrays = leftChars.split(',') - for aItemIndex in range(0, len(dataArrays), 13): - ''' - 日期 - 收盘价 - 涨跌幅 - 主力净流入 净额 净占比 - 超大单净流入 净额 净占比 - 大单净流入 净额 净占比 - 中单净流入 净额 净占比 - 小单净流入 净额 净占比 - ''' - dict_row = {} - - dict_row['stock_code'] = param_stock_code_list[iStockCode] - - # 日期 - data01 = dataArrays[aItemIndex] - data01 = data01.strip('"') - - dict_row['date'] = data01 - - # 主力净流入 净额 - data02 = dataArrays[aItemIndex + 1] - data02 = data02.strip('"') - - dict_row['zljll_je_wy'] = data02 - - # 主力净流入 净占比 - data03 = dataArrays[aItemIndex + 2] - data03 = data03.strip('"') - - dict_row['zljll_jzb_bfb'] = data03 - - # 超大单净流入 净额 - data04 = dataArrays[aItemIndex + 3] - data04 = data04.strip('"') - - dict_row['cddjll_je_wy'] = data04 - - # 超大单净流入 净占比 - data05 = dataArrays[aItemIndex + 4] - data05 = data05.strip('"') - - dict_row['cddjll_je_jzb'] = data05 - - # 大单净流入 净额 - data06 = dataArrays[aItemIndex + 5] - data06 = data06.strip('"') - - dict_row['ddjll_je_wy'] = data06 - - # 大单净流入 净占比 - data07 = dataArrays[aItemIndex + 6] - data07 = data07.strip('"') - - dict_row['ddjll_je_jzb'] = data07 - - # 中单净流入 净额 - data08 = dataArrays[aItemIndex + 7] - data08 = data08.strip('"') - - dict_row['zdjll_je_wy'] = data08 - - # 中单净流入 净占比 - data09 = dataArrays[aItemIndex + 8] - data09 = data09.strip('"') - - dict_row['zdjll_je_jzb'] = data09 - - # 小单净流入 净额 - data10 = dataArrays[aItemIndex + 9] - data10 = data10.strip('"') - - dict_row['xdjll_je_wy'] = data10 - - # 小单净流入 净占比 - data11 = dataArrays[aItemIndex + 10] - data11 = data11.strip('"') - - dict_row['xdjll_je_jzb'] = data11 - - # 收盘价 - data12 = dataArrays[aItemIndex + 11] - data12 = data12.strip('"') - - dict_row['close_price'] = data12 - - # 涨跌幅 - data13 = dataArrays[aItemIndex + 12] - data13 = data13.strip('"') - data13 = data13.strip('"]]})') - - dict_row['change_price'] = data13 - - # 读取一条记录成功 - list_data_zjlx.append(dict_row) - - # print(list_data_zjlx) - - df = pd.DataFrame(list_data_zjlx) - - # print(df) - - client = DATABASE - coll_stock_zjlx = client.eastmoney_stock_zjlx - - # coll_stock_zjlx.insert_many(QA_util_to_json_from_pandas(df)) - - for i in range(len(list_data_zjlx)): - aRec = list_data_zjlx[i] - - # 🛠todo 当天结束后,获取当天的资金流相,当天的资金流向是瞬时间点的 - ret = coll_stock_zjlx.find_one(aRec) - if ret == None: - coll_stock_zjlx.insert_one(aRec) - print("🤑 插入新的记录 ", aRec) - else: - print("😵 记录已经存在 ", ret) - - -''' - 作为测试用例来获取, 对比 reqeust 方式的获取数据是否一致 -''' -def QA_read_eastmoney_zjlx_web_page_to_sqllite(stockCodeList = None): - - # todo 🛠 check stockCode 是否存在有效合法 - # todo 🛠 QALocalize 从QALocalize 目录中读取 固定位置存放驱动文件 - - print("📨当前工作路径文件位置 : ",os.getcwd()) - path_check = os.getcwd()+"/QUANTAXIS_WEBDRIVER" - if os.path.exists(path_check) == False: - print("😵 确认当前路径是否包含selenium_driver目录 😰 ") - return - else: - print(os.getcwd()+"/QUANTAXIS_WEBDRIVER"," 目录存在 😁") - print("") - - # path_for_save_data = QALocalize.download_path + "/eastmoney_stock_zjlx" - # isExists = os.path.exists(path_for_save_data) - # if isExists == False: - # os.mkdir(path_for_save_data) - # isExists = os.path.exists(path_for_save_data) - # if isExists == True: - # print(path_for_save_data,"目录不存在! 成功建立目录 😢") - # else: - # print(path_for_save_data,"目录不存在! 失败建立目录 🤮, 可能没有权限 🈲") - # return - # else: - # print(path_for_save_data,"目录存在!准备读取数据 😋") - - browser = open_chrome_driver() - - for indexCode in range(len(stockCodeList)): - #full_path_name = path_for_save_data + "/" + stockCodeList[indexCode] + "_zjlx.sqlite.db" - read_east_money_page_zjlx_to_sqllite(stockCodeList[indexCode], browser) - pass - close_chrome_dirver(browser) - #创建目录 - #启动线程读取网页,写入数据库 - #等待完成 \ No newline at end of file diff --git a/QUANTAXIS/QASU/crawl_jrj_financial_reportdate.py b/QUANTAXIS/QASU/crawl_jrj_financial_reportdate.py deleted file mode 100644 index 5c26f86ee..000000000 --- a/QUANTAXIS/QASU/crawl_jrj_financial_reportdate.py +++ /dev/null @@ -1,92 +0,0 @@ - -from QUANTAXIS.QAFetch.QAcalendar import * -from QUANTAXIS.QAUtil import (DATABASE,QA_util_getBetweenQuarter, QA_util_get_next_day, - QA_util_get_real_date, QA_util_log_info,QA_util_add_months, - QA_util_to_json_from_pandas, trade_date_sse,QA_util_today_str, - QA_util_datetime_to_strdate) -import pandas as pd -import pymongo - -def QA_SU_save_report_calendar_day(client=DATABASE, ui_log = None, ui_progress = None): - ''' - save stock_day - 保存财报日历 - 历史全部数据 - :return: - ''' - END_DATE = QA_util_datetime_to_strdate(QA_util_add_months(QA_util_today_str(),-3)) - START_DATE = QA_util_datetime_to_strdate(QA_util_add_months(QA_util_today_str(),-12)) - - date_list = list(pd.DataFrame.from_dict(QA_util_getBetweenQuarter(START_DATE,END_DATE)).T.iloc[:,1]) - report_calendar = client.report_calendar - report_calendar.create_index([("code", pymongo.ASCENDING), ("report_date", pymongo.ASCENDING)], unique=True) - err = [] - - def __saving_work(report_date, report_calendar): - try: - QA_util_log_info( - '##JOB01 Now Saving Report_Calendar==== {}'.format(str(report_date)), ui_log) - - report_calendar.insert_many(QA_util_to_json_from_pandas( - QA_fetch_get_financial_calendar(report_date)), ordered=False) - except Exception as error0: - print(error0) - err.append(str(report_date)) - - for item in date_list: - - QA_util_log_info('The {} of Total {}'.format - ((date_list.index(item) +1), len(date_list))) - - strProgressToLog = 'DOWNLOAD PROGRESS {}'.format(str(float((date_list.index(item) +1) / len(date_list) * 100))[0:4] + '%', ui_log) - intProgressToLog = int(float((date_list.index(item) +1) / len(date_list) * 100)) - QA_util_log_info(strProgressToLog, ui_log= ui_log, ui_progress= ui_progress, ui_progress_int_value= intProgressToLog) - - __saving_work( item, report_calendar) - - if len(err) < 1: - QA_util_log_info('SUCCESS save report calendar ^_^', ui_log) - else: - QA_util_log_info(' ERROR CODE \n ', ui_log) - QA_util_log_info(err, ui_log) - - -def QA_SU_save_report_calendar_his(client=DATABASE, ui_log = None, ui_progress = None): - ''' - save stock_day - 保存财报日历 - 反向查询四个季度财报 - :return: - ''' - START_DATE = '1996-01-01' - END_DATE = QA_util_datetime_to_strdate(QA_util_add_months(QA_util_today_str(),-3)) - date_list = list(pd.DataFrame.from_dict(QA_util_getBetweenQuarter(START_DATE,END_DATE)).T.iloc[:,1]) - report_calendar = client.report_calendar - report_calendar.create_index([("code", pymongo.ASCENDING), ("report_date", pymongo.ASCENDING)], unique=True) - err = [] - - def __saving_work(report_date, report_calendar): - try: - QA_util_log_info( - '##JOB01 Now Saving Report_Calendar==== {}'.format(str(report_date)), ui_log) - report_calendar.insert_many(QA_util_to_json_from_pandas( - QA_fetch_get_financial_calendar(report_date)), ordered=False) - except Exception as error0: - print(error0) - err.append(str(report_date)) - - for item in date_list: - QA_util_log_info('The {} of Total {}'.format - ((date_list.index(item) +1), len(date_list))) - - strProgressToLog = 'DOWNLOAD PROGRESS {}'.format(str(float((date_list.index(item) +1) / len(date_list) * 100))[0:4] + '%', ui_log) - intProgressToLog = int(float((date_list.index(item) + 1)/ len(date_list) * 100)) - QA_util_log_info(strProgressToLog, ui_log= ui_log, ui_progress= ui_progress, ui_progress_int_value= intProgressToLog) - - __saving_work( item, report_calendar) - - if len(err) < 1: - QA_util_log_info('SUCCESS save report calendar ^_^', ui_log) - else: - QA_util_log_info(' ERROR CODE \n ', ui_log) - QA_util_log_info(err, ui_log) \ No newline at end of file diff --git a/QUANTAXIS/QASU/crawl_jrj_stock_divyield.py b/QUANTAXIS/QASU/crawl_jrj_stock_divyield.py deleted file mode 100644 index bbd5a3e3b..000000000 --- a/QUANTAXIS/QASU/crawl_jrj_stock_divyield.py +++ /dev/null @@ -1,92 +0,0 @@ - -from QUANTAXIS.QAFetch.QAdivyield import * -from QUANTAXIS.QAUtil import (DATABASE,QA_util_getBetweenQuarter, QA_util_get_next_day, - QA_util_get_real_date, QA_util_log_info,QA_util_add_months, - QA_util_to_json_from_pandas, trade_date_sse,QA_util_today_str, - QA_util_datetime_to_strdate) -import pandas as pd -import pymongo - -def QA_SU_save_stock_divyield_day(client=DATABASE, ui_log = None, ui_progress = None): - ''' - save stock_day - 保存财报日历 - 历史全部数据 - :return: - ''' - END_DATE = QA_util_datetime_to_strdate(QA_util_add_months(QA_util_today_str(),-3)) - START_DATE = QA_util_datetime_to_strdate(QA_util_add_months(QA_util_today_str(),-12)) - - date_list = list(pd.DataFrame.from_dict(QA_util_getBetweenQuarter(START_DATE,END_DATE)).T.iloc[:,1]) - stock_divyield = client.stock_divyield - stock_divyield.create_index([("a_stockcode", pymongo.ASCENDING), ("dir_dcl_date", pymongo.ASCENDING)], unique=True) - err = [] - - def __saving_work(report_date, stock_divyield): - try: - QA_util_log_info( - '##JOB01 Now Saving stock_divyield==== {}'.format(str(report_date)), ui_log) - - stock_divyield.insert_many(QA_util_to_json_from_pandas( - QA_fetch_get_stock_divyield(report_date)), ordered=False) - except Exception as error0: - print(error0) - err.append(str(report_date)) - - for item in date_list: - - QA_util_log_info('The {} of Total {}'.format - ((date_list.index(item) +1), len(date_list))) - - strProgressToLog = 'DOWNLOAD PROGRESS {}'.format(str(float((date_list.index(item) +1) / len(date_list) * 100))[0:4] + '%', ui_log) - intProgressToLog = int(float((date_list.index(item) +1) / len(date_list) * 100)) - QA_util_log_info(strProgressToLog, ui_log= ui_log, ui_progress= ui_progress, ui_progress_int_value= intProgressToLog) - - __saving_work( item, stock_divyield) - - if len(err) < 1: - QA_util_log_info('SUCCESS save stock divyield ^_^', ui_log) - else: - QA_util_log_info(' ERROR CODE \n ', ui_log) - QA_util_log_info(err, ui_log) - - -def QA_SU_save_stock_divyield_his(client=DATABASE, ui_log = None, ui_progress = None): - ''' - save stock_day - 保存财报日历 - 反向查询四个季度财报 - :return: - ''' - START_DATE = '2007-01-01' - END_DATE = QA_util_datetime_to_strdate(QA_util_add_months(QA_util_today_str(),-3)) - date_list = list(pd.DataFrame.from_dict(QA_util_getBetweenQuarter(START_DATE,END_DATE)).T.iloc[:,1]) - stock_divyield = client.stock_divyield - stock_divyield.create_index([("a_stockcode", pymongo.ASCENDING), ("report_date", pymongo.ASCENDING)], unique=True) - err = [] - - def __saving_work(report_date, stock_divyield): - try: - QA_util_log_info( - '##JOB01 Now Saving stock_divyield==== {}'.format(str(report_date)), ui_log) - stock_divyield.insert_many(QA_util_to_json_from_pandas( - QA_fetch_get_stock_divyield(report_date)), ordered=False) - except Exception as error0: - print(error0) - err.append(str(report_date)) - - for item in date_list: - QA_util_log_info('The {} of Total {}'.format - ((date_list.index(item) +1), len(date_list))) - - strProgressToLog = 'DOWNLOAD PROGRESS {}'.format(str(float((date_list.index(item) +1) / len(date_list) * 100))[0:4] + '%', ui_log) - intProgressToLog = int(float((date_list.index(item) + 1)/ len(date_list) * 100)) - QA_util_log_info(strProgressToLog, ui_log= ui_log, ui_progress= ui_progress, ui_progress_int_value= intProgressToLog) - - __saving_work( item, stock_divyield) - - if len(err) < 1: - QA_util_log_info('SUCCESS save stock divyield ^_^', ui_log) - else: - QA_util_log_info(' ERROR CODE \n ', ui_log) - QA_util_log_info(err, ui_log) \ No newline at end of file diff --git a/QUANTAXIS/QASU/main.py b/QUANTAXIS/QASU/main.py index e8bbd6677..179a737c4 100755 --- a/QUANTAXIS/QASU/main.py +++ b/QUANTAXIS/QASU/main.py @@ -22,14 +22,14 @@ # SOFTWARE. from QUANTAXIS.QAFetch.QAQuery import QA_fetch_stock_list -from QUANTAXIS.QASU import crawl_eastmoney as crawl_eastmoney_file +#from QUANTAXIS.QASU import crawl_eastmoney as crawl_eastmoney_file from QUANTAXIS.QASU import save_tdx as stdx from QUANTAXIS.QASU import save_tdx_file as tdx_file from QUANTAXIS.QASU import save_tushare as sts from QUANTAXIS.QASU import save_financialfiles from QUANTAXIS.QAUtil import DATABASE -from QUANTAXIS.QASU import crawl_jrj_financial_reportdate as save_financial_calendar -from QUANTAXIS.QASU import crawl_jrj_stock_divyield as save_stock_divyield +# from QUANTAXIS.QASU import crawl_jrj_financial_reportdate as save_financial_calendar +# from QUANTAXIS.QASU import crawl_jrj_stock_divyield as save_stock_divyield def QA_SU_save_stock_info(engine, client=DATABASE): diff --git a/QUANTAXIS/QASU/save_to_db_fields_description.py b/QUANTAXIS/QASU/save_to_db_fields_description.py deleted file mode 100644 index acf32784d..000000000 --- a/QUANTAXIS/QASU/save_to_db_fields_description.py +++ /dev/null @@ -1,100 +0,0 @@ - -''' - -''' -quantaxis__db_description= [ - - { - 'stock_info_tushare': - [ - {'code':'代码'}, - {'name','名称'}, - {'industry','所属行业'}, - {'area','地区'}, - {'pe','市盈率'}, - {'outstanding','流通股本(亿)'}, - {'totals','总股本(亿)'}, - {'totalAssets','总资产(万)'}, - {'liquidAssets','流动资产'}, - {'fixedAssets','固定资产'}, - {'reserved','公积金'}, - {'reservedPerShare','每股公积金'}, - {'esp','每股收益'}, - {'bvps','每股净资'}, - {'pb','市净率'}, - {'timeToMarket','上市日期'}, - {'undp','未分利润'}, - {'perundp', '每股未分配'}, - {'rev','收入同比(%)'}, - {'profit','利润同比(%)'}, - {'gpr','毛利率(%)'}, - {'npr','净利润率(%)'}, - {'holders','股东人数'}, - ] - }, - { - 'stock_info': - [ - {"market": '1'}, - {"code": "代码"}, - {"liutongguben": '流通股本(单位)'}, - {"province": "省市代码区域"}, - {"industry": "行业分类代码"}, - {"updated_date": '最后更新时间'}, - {"ipo_date": "首次公开发行日期"}, - {"zongguben": "总股本"}, - {"guojiagu": "国家股"}, - {"faqirenfarengu": "发起人法人股"}, - {"farengu": "法人股"}, - {"bgu": "B股"}, - {"hgu": "H股"}, - {"zhigonggu": "职工股"}, - {"zongzichan": "总资产"}, - {"liudongzichan": "流动资产"}, - {"gudingzichan": "固定资产"}, - {"wuxingzichan": "无形资产"}, - {"gudongrenshu": "股东人数"}, - {"liudongfuzhai": "流动负责"}, - {"changqifuzhai": "长期负责"}, - {"zibengongjijin": "资本公积金"}, - {"jingzichan": "净资产"}, - {"zhuyingshouru": "主营收入"}, - {"zhuyinglirun": "主营利润"}, - {"yingshouzhangkuan": "营收账款"}, - {"yingyelirun": "营业利润"}, - {"touzishouyu": "投资收益"}, - {"jingyingxianjinliu": "经营现金流"}, - {"zongxianjinliu": "总现金流"}, - {"cunhuo": "存货"}, - {"lirunzonghe": "利润总和"}, - {"shuihoulirun": "税后利润"}, - {"jinglirun": "净利润"}, - {"weifenpeilirun": "未分配利润"}, - {"meigujingzichan": "每股净资产"}, - {"baoliu2": "保留"} - ] - }, - { - 'eastmoney_stock_zjlx': - [ - {"stock_code" : "股票代码"}, - {"date" : "日期"}, - {"zljll_je_wy" : "主力资金流入(金额)单位万元"}, - {"zljll_jzb_bfb" : "主力资金流入(净占比)%"}, - {"cddjll_je_wy" : "超级大单流入(金额)单位万元"}, - {"cddjll_je_jzb" : "超级大单流入(净占比)"}, - {"ddjll_je_wy" : "大单资金流入(金额)单位万元"}, - {"ddjll_je_jzb" : "大单资金流入(净占比)%"}, - {"zdjll_je_wy" : "中单资金流入(金额)单位万元"}, - {"zdjll_je_jzb" : "中单资金流入(净占比)%"}, - {"xdjll_je_wy" : "小单资金流入(金额)单位万元"}, - {"xdjll_je_jzb" : "小单资金流入(净占比)"}, - {"close_price" : "收盘价"}, - {"change_price" : "涨跌幅"} - ] - } - - - -] - From 5ae5f68d8a0afc066a3afb7133484300611bb4c7 Mon Sep 17 00:00:00 2001 From: yutiansut Date: Tue, 15 Jan 2019 02:54:36 +0800 Subject: [PATCH 5/5] #update --- CHANGELOG.md | 19 + QUANTAXIS_Monitor_GUI/AppMediator.py | 608 -------------- .../MainTabWindows/Tab00_WelcomeSplash.py | 57 -- .../MainTabWindows/Tab01_DataMaintenance.py | 552 ------------- .../Tab02_WebpageCrawly_Old_no_use.py | 540 ------------- .../Tab02_WebpageEastMoneyZJLX.py | 707 ---------------- .../MainTabWindows/Tab03_DataCheck.py | 0 .../MainTabWindows/Tab04_BlockStatistics.py | 413 ---------- .../Tab05_StrategyBacktraceRuning.py | 27 - .../Tab06_ForecastStockTrends.py | 263 ------ .../MainTabWindows/Tab0_RootClass.py | 25 - .../MainTabWindows/__init__.py | 0 .../splash_html_page/images/donation_rq.png | Bin 54831 -> 0 bytes .../splash_html_page/images/quantaxis.png | Bin 7433 -> 0 bytes .../splash_html_page/splash.html | 32 - QUANTAXIS_Monitor_GUI/MainWin.py | 93 --- .../MainWindow/TabDataMaintenance.py | 380 --------- .../MyQtWidgets/MyDrawImgs/QStockDateRuler.py | 228 ------ .../MyQtWidgets/MyDrawImgs/QStockGMMA.py | 415 ---------- .../MyQtWidgets/MyDrawImgs/QStockInfo.py | 92 --- .../MyQtWidgets/MyDrawImgs/QStockKLine.py | 183 ----- .../MyDrawImgs/QStockLeftPriceRuler.py | 104 --- .../MyQtWidgets/MyDrawImgs/QStockMouseMove.py | 67 -- .../MyQtWidgets/MyDrawImgs/__init__.py | 0 .../QStockPriceCanvas_old_no_use.py | 690 ---------------- .../MyQtWidgets/QStockPriceVolumeCanvas.py | 394 --------- QUANTAXIS_Monitor_GUI/MyQtWidgets/__init__.py | 0 .../ProgressDlgs/ProgressDlg_Timeout.py | 60 -- .../ProgressDlgs/ProgressDlg_WithThreading.py | 68 -- .../ProgressDlgs/__init__.py | 0 .../TasksByProcess/SubProcessFetchZJLX.py | 520 ------------ .../SubSeleniumProcess_not_used.py | 357 --------- .../TasksByProcess/__init__.py | 0 .../TasksByThreading/QA_Gui_DateFetch_Task.py | 737 ----------------- .../QThread_CheckStockBlock_DB_Task.py | 169 ---- .../QThread_CheckZJLX_DB_Task.py | 295 ------- .../TasksByThreading/QThread_FetchWebPage.py | 752 ------------------ .../QThread_GetStockList_Partition.py | 36 - .../TasksByThreading/QThread_RootClass.py | 14 - .../TasksByThreading/__init__.py | 0 QUANTAXIS_Monitor_GUI/Utils/__init__.py | 0 .../Utils/mongodb_start_stop.sh | 62 -- QUANTAXIS_Monitor_GUI/__init__.py | 0 43 files changed, 19 insertions(+), 8940 deletions(-) delete mode 100644 QUANTAXIS_Monitor_GUI/AppMediator.py delete mode 100644 QUANTAXIS_Monitor_GUI/MainTabWindows/Tab00_WelcomeSplash.py delete mode 100644 QUANTAXIS_Monitor_GUI/MainTabWindows/Tab01_DataMaintenance.py delete mode 100644 QUANTAXIS_Monitor_GUI/MainTabWindows/Tab02_WebpageCrawly_Old_no_use.py delete mode 100644 QUANTAXIS_Monitor_GUI/MainTabWindows/Tab02_WebpageEastMoneyZJLX.py delete mode 100644 QUANTAXIS_Monitor_GUI/MainTabWindows/Tab03_DataCheck.py delete mode 100644 QUANTAXIS_Monitor_GUI/MainTabWindows/Tab04_BlockStatistics.py delete mode 100644 QUANTAXIS_Monitor_GUI/MainTabWindows/Tab05_StrategyBacktraceRuning.py delete mode 100644 QUANTAXIS_Monitor_GUI/MainTabWindows/Tab06_ForecastStockTrends.py delete mode 100644 QUANTAXIS_Monitor_GUI/MainTabWindows/Tab0_RootClass.py delete mode 100644 QUANTAXIS_Monitor_GUI/MainTabWindows/__init__.py delete mode 100644 QUANTAXIS_Monitor_GUI/MainTabWindows/splash_html_page/images/donation_rq.png delete mode 100644 QUANTAXIS_Monitor_GUI/MainTabWindows/splash_html_page/images/quantaxis.png delete mode 100644 QUANTAXIS_Monitor_GUI/MainTabWindows/splash_html_page/splash.html delete mode 100644 QUANTAXIS_Monitor_GUI/MainWin.py delete mode 100644 QUANTAXIS_Monitor_GUI/MainWindow/TabDataMaintenance.py delete mode 100644 QUANTAXIS_Monitor_GUI/MyQtWidgets/MyDrawImgs/QStockDateRuler.py delete mode 100644 QUANTAXIS_Monitor_GUI/MyQtWidgets/MyDrawImgs/QStockGMMA.py delete mode 100644 QUANTAXIS_Monitor_GUI/MyQtWidgets/MyDrawImgs/QStockInfo.py delete mode 100644 QUANTAXIS_Monitor_GUI/MyQtWidgets/MyDrawImgs/QStockKLine.py delete mode 100644 QUANTAXIS_Monitor_GUI/MyQtWidgets/MyDrawImgs/QStockLeftPriceRuler.py delete mode 100644 QUANTAXIS_Monitor_GUI/MyQtWidgets/MyDrawImgs/QStockMouseMove.py delete mode 100644 QUANTAXIS_Monitor_GUI/MyQtWidgets/MyDrawImgs/__init__.py delete mode 100644 QUANTAXIS_Monitor_GUI/MyQtWidgets/QStockPriceCanvas_old_no_use.py delete mode 100644 QUANTAXIS_Monitor_GUI/MyQtWidgets/QStockPriceVolumeCanvas.py delete mode 100644 QUANTAXIS_Monitor_GUI/MyQtWidgets/__init__.py delete mode 100644 QUANTAXIS_Monitor_GUI/ProgressDlgs/ProgressDlg_Timeout.py delete mode 100644 QUANTAXIS_Monitor_GUI/ProgressDlgs/ProgressDlg_WithThreading.py delete mode 100644 QUANTAXIS_Monitor_GUI/ProgressDlgs/__init__.py delete mode 100644 QUANTAXIS_Monitor_GUI/TasksByProcess/SubProcessFetchZJLX.py delete mode 100644 QUANTAXIS_Monitor_GUI/TasksByProcess/SubSeleniumProcess_not_used.py delete mode 100644 QUANTAXIS_Monitor_GUI/TasksByProcess/__init__.py delete mode 100644 QUANTAXIS_Monitor_GUI/TasksByThreading/QA_Gui_DateFetch_Task.py delete mode 100644 QUANTAXIS_Monitor_GUI/TasksByThreading/QThread_CheckStockBlock_DB_Task.py delete mode 100644 QUANTAXIS_Monitor_GUI/TasksByThreading/QThread_CheckZJLX_DB_Task.py delete mode 100644 QUANTAXIS_Monitor_GUI/TasksByThreading/QThread_FetchWebPage.py delete mode 100644 QUANTAXIS_Monitor_GUI/TasksByThreading/QThread_GetStockList_Partition.py delete mode 100644 QUANTAXIS_Monitor_GUI/TasksByThreading/QThread_RootClass.py delete mode 100644 QUANTAXIS_Monitor_GUI/TasksByThreading/__init__.py delete mode 100644 QUANTAXIS_Monitor_GUI/Utils/__init__.py delete mode 100644 QUANTAXIS_Monitor_GUI/Utils/mongodb_start_stop.sh delete mode 100644 QUANTAXIS_Monitor_GUI/__init__.py diff --git a/CHANGELOG.md b/CHANGELOG.md index 3b0e792ba..663097bc6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -73,6 +73,25 @@ - [1.0.25](#1025) +## 1.2.7 + +迁移目录: + +1. 拆分 QUANTAXIS_CRAWLY 至 https://github.com/QUANTAXIS/QUANTAXIS_CRAWLY + +- 减少twisted安装问题 +- 模块解耦 功能分离 + +2. 拆分 QUANTAXIS_MONITOR_GUI 至 https://github.com/QUANTAXIS/QUANTAXIS_Monitor_GUI + +- gui部分以插件形式提供 + +3. 使用yapf 大量修正格式 + + + + + ## 1.2.6 1. 优化QADOCKER文档 diff --git a/QUANTAXIS_Monitor_GUI/AppMediator.py b/QUANTAXIS_Monitor_GUI/AppMediator.py deleted file mode 100644 index c51bac3ac..000000000 --- a/QUANTAXIS_Monitor_GUI/AppMediator.py +++ /dev/null @@ -1,608 +0,0 @@ -''' -https://sourcemaking.com/design_patterns/mediator/python/1 -''' -import sys -import os -import threading -import subprocess -import time -import socket - -from PyQt5.QtCore import * -from PyQt5.QtGui import * -from PyQt5.QtWidgets import * -from PyQt5 import QtCore, QtGui, QtWidgets - -from datetime import datetime - -from QUANTAXIS_Monitor_GUI.MainTabWindows.Tab02_WebpageEastMoneyZJLX import processNumber -from QUANTAXIS_Monitor_GUI.MainTabWindows.Tab02_WebpageEastMoneyZJLX import portNumberStart - - -from QUANTAXIS_Monitor_GUI.ProgressDlgs.ProgressDlg_Timeout import * -from QUANTAXIS_Monitor_GUI.ProgressDlgs.ProgressDlg_WithThreading import * - - -from QUANTAXIS_Monitor_GUI.TasksByThreading.QThread_GetStockList_Partition import * -from QUANTAXIS_Monitor_GUI.TasksByThreading.QThread_CheckZJLX_DB_Task import * -from QUANTAXIS_Monitor_GUI.TasksByThreading.QThread_FetchWebPage import * - - -from QUANTAXIS_Monitor_GUI.TasksByThreading.QA_Gui_DateFetch_Task import * - - - -from QUANTAXIS.QAUtil.QASetting import * - -#enum 有坑,容易造成第三方名字冲突 -#https://blog.csdn.net/appleyk/article/details/77934767 -#https://www.cnblogs.com/fyqx/p/6985902.html - - -class Mediator: - """ - Implement cooperative behavior by coordinating Colleague objects. - Know and maintains its colleagues. - """ - ######################################################################################################## - processList = [] # process object - strProcessStateTerminated = "ProcessTerminated" - strProcessStateStartupFailed = "ProcessStartupFailed" - strProcessStateRunning = "ProcessRunning" - strProcessStateNoResponse = "ProcessNoResponse" - strProcessStateError= "ProcessStateError" - strCurrentProcessState = [] # = strProcessStateTerminated - - ######################################################################################################## - threadList =[] # thread objecg - strThreadStateTerminated= "ThreadTerminated" - strThreadStateRunning = "ThreadRunning" - strCurrentThreadState = [] - - ######################################################################################################## - currentNeedUpdateStockCodeList = [] - cuurentNeedUpdateCodeSegmentCountLists = [] - currentNeedUpdateCodeSegemenStockList = [] #list in list - - #每个线程上一次成功完成获取的点 - lastTimeProgressCheckPoint = [] - - ######################################################################################################## - - def __init__(self): - - for iIndex in range(processNumber): - self.processList.append(None) - self.threadList.append(None) - self.strCurrentProcessState.append(self.strProcessStateTerminated) - self.strCurrentThreadState.append(self.strThreadStateTerminated) - self.lastTimeProgressCheckPoint.append(0) - - self.currentNeedUpdateCodeSegemenStockList.append(None) - self.currentNeedUpdateStockCodeList.append(None) - self.cuurentNeedUpdateCodeSegmentCountLists.append(0) - - pass - - def try_connect_server(self, strAddress, strPort): - connectedOk = False - try: - sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - server_address = (strAddress, int(strPort)) - sock.settimeout(5.0) - sock.connect(server_address) - - # data = sock.recv(128) - # if len(data) == 128: - # - # cmdString = data.decode(); - # cmdArry = cmdString.split('@') - # cmd = cmdArry[0].strip('0') - # parame = cmdArry[1] - # if (cmd == 'state' and parame == 'process_start_ok'): - # connectedOk = True - # else: - # connectedOk = False - # else: - # connectedOk = False - connectedOk = True - except Exception as ee: - strError = ee.__str__() - print(strError) - finally: - sock.close() - - return connectedOk - - - def try_connect_server_and_shutdown_process(self,strAddress, strPort): - shutdownOk = False - try: - sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - server_address = (strAddress, int(strPort)) - sock.connect(server_address) - - ############################################################# - strMsg0 = "shutdown_process@shutdown_process" - bytes_content = strMsg0.encode() - bytes_content = bytes_content.zfill(128) - assert (len(bytes_content) == 128) - # 🛠todo fix 128 个byte 很傻 - sock.sendall(bytes_content) - ############################################################# - # - # - # data = sock.recv(128) - # if len(data) == 128: - # - # cmdString = data.decode(); - # cmdArry = cmdString.split('@') - # cmd = cmdArry[0].strip('0') - # parame = cmdArry[1] - # if (cmd == 'state' and parame == 'shutdown_procceed'): - # shutdownOk = True - # else: - # shutdownOk = False - shutdownOk = True - except Exception as ee: - strError = ee.__str__() - print(strError) - finally: - sock.close() - - return shutdownOk - - def startUpEastMoneyZjlxProcess(self, parentWnd, iProcessIndex, strAddress, strPort): - print(strAddress,' ', strPort) - - if self.getCurrentProcessState(iProcessIndex) == self.strProcessStateRunning: - msg = QMessageBox() - msg.setIcon(QMessageBox.Information) - msg.setText("已经启动了,正在工作中!😹 ") - msg.setInformativeText("已经启动了,正在工作中😹 ") - msg.setWindowTitle("操作提示:") - msg.setDetailedText("已经启动了,正在工作中") - retval = msg.exec() - return; - - - ui_log = parentWnd.trigger_sub_process_operation_log_by_index(iProcessIndex) - - try: - - #self.try_connect_server_and_shutdown_process(strAddress, strPort) - - # xxxx/QUANTAXIS/QUANTAXIS_Monitor_GUI/MainTables/__file__ - realPath = os.path.realpath(__file__) # xxxx/QUANTAXIS/QUANTAXIS_Monitor_GUI/__file__ - realDir1 = os.path.dirname(realPath); # xxxx/QUANTAXIS/QUANTAXIS_Monitor_GUI - realDir2 = os.path.dirname(realDir1); - - p = subprocess.Popen( - ['python', './QUANTAXIS_Monitor_GUI/TasksByProcess/SubProcessFetchZJLX.py', (strPort)], - cwd=realDir2) - #stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) - - #第一次尝试30次 - tryCount = 0 - while True: - boolConnectOk = self.try_connect_server(strAddress, strPort) - if boolConnectOk == False: - strMsg = " 🐢正在subprocess启动未完成, #{}进程 地址{}, 端口{} ,⌛️耐心等待️⌛ 第%d次尝试 ".format(iProcessIndex, strAddress, strPort,tryCount) - ui_log.emit(strMsg) - dlg = ProgressDlg_Timeout(parent=None, timeOut=2, userHint=strMsg) - dlg.exec() - - tryCount = tryCount + 1 - if tryCount > 30: - break - else: - break - - - if boolConnectOk == False: - msg = QMessageBox() - #msg.setWindowFlags(Qt) - strMsg = " 🐢正在subprocess启动失败 \n #{}进程 地址{}, 端口{} \n ❌启动失败,无法连接 startUpEastMoneyZjlxProcess❌".format(iProcessIndex, strAddress, strPort) - ui_log.emit(strMsg) - msg.setText(strMsg) - msg.exec() - - # p.terminate() - # print('强制退出进程') - - ui_log.emit('❌启动失败,无法连接 startUpEastMoneyZjlxProcess❌') - - self.strCurrentProcessState[iProcessIndex] = self.strProcessStateStartupFailed - return False - else: - self.strCurrentProcessState[iProcessIndex] = self.strProcessStateRunning - - - - if self.processList[iProcessIndex] is None: - self.processList[iProcessIndex] = p - ui_log.emit('✅启动成功,开始等待命令✅') - - else: - # 不应该执行到这里 - self.strCurrentProcessState[iProcessIndex] = self.strProcessStateError - - # p = self.processList[iProcessIndex] - # p.terminate() - # print('强制退出进程') - # p = None - # ui_log.emit('❌系统错误,退出进程!startUpEastMoneyZjlxProcess 强制退出进程 ❌') - # dlg = ProgressDlg_Timeout(parent=None, timeOut=10, userHint=" ❌系统错误,退出进程!❌") - # dlg.exec() - #self.processList[iProcessIndex] = p - - return False - - print(p) - #等待返回OK 尝试连接socket 服务程序 - #查询就绪命令 - self.strCurrentProcessState[iProcessIndex] = self.strProcessStateRunning - return True - - except Exception as ee: - strError = ee.__str__() - print(strError) - - #self.shutdownEastMoneyZjlxProcess(self,iProcessIndex,strAddress,strPort) - self.strCurrentProcessState[iProcessIndex] = self.strProcessStateStartupFailed - return False - - - - def shutdownEastMoneyZjlxProcess(self, parentWnd, iProcessIndex, strAddress, strPort): - print(strAddress, ' ', strPort) - - - # if self.getCurrentProcessState(iProcessIndex) != self.strProcessStateRunning: - # msg = QMessageBox() - # msg.setIcon(QMessageBox.Information) - # msg.setText("进程已经停止了!😹 ") - # msg.setInformativeText("进程已经停止了😹 ") - # msg.setWindowTitle("操作提示:") - # msg.setDetailedText("进程已经停止了") - # retval = msg.exec() - # return; - - if self.getCurrentThreadState(iProcessIndex) != self.strThreadStateTerminated: - msg = QMessageBox() - msg.setIcon(QMessageBox.Information) - msg.setText("线程没有停止,请先停止线程!😹 ") - msg.setInformativeText("线程没有停止,请先停止线程😹 ") - msg.setWindowTitle("操作提示:") - msg.setDetailedText("线程没有停止,请先停止线程") - retval = msg.exec() - return - - ui_log = parentWnd.trigger_sub_process_operation_log_by_index(iProcessIndex) - - # 等待返回OK 尝试连接socket 服务程序 - # 发送关闭命令 - p = self.processList[iProcessIndex] - - # 第一次尝试30次 - tryCount = 0 - while True: - - tryCount = tryCount + 1 - - bCanConnect = self.try_connect_server_and_shutdown_process(strAddress,strPort) - if bCanConnect == True: - strMsg = " ☄️正在关闭 #{}进程 地址{}, 端口{} ⌛️耐心等待️⌛ ".format(iProcessIndex, strAddress, strPort) - ui_log.emit(strMsg) - dlg = ProgressDlg_Timeout(parent=None, timeOut=5, userHint=strMsg) - dlg.exec() - else: - break - - if tryCount > 30: - break - - - - - bCoonectOk = self.try_connect_server(strAddress, strPort) - if bCoonectOk == False: - - strLog = "❓💤进程%d 结束成功 💤❓" % iProcessIndex - ui_log.emit(strLog) - self.strCurrentProcessState[iProcessIndex] = self.strProcessStateTerminated - - else: - ui_log.emit("❌进程结束失败❌") - self.strCurrentProcessState[iProcessIndex] = self.strProcessStateRunning - - #time.sleep(2) - if p is not None: - # 强制退出 - #p.terminate() - #print('强制退出进程') - #p.poll() - p = None - self.processList[iProcessIndex] = None - - self.strCurrentProcessState[iProcessIndex] = self.strProcessStateTerminated - - #bCoonectOk = self.try_connect_server(strAddress, strPort) - #if bCoonectOk == True: - # self.strCurrentProcessState[iProcessIndex] = self.strProcessStateError - else: - - #dlg = ProgressDlg_Timeout(parent=None, timeOut=60, userHint=" ❌系统错误,退出进程!shutdownEastMoneyZjlxProcess❌") - #dlg.exec() - - self.strCurrentProcessState[iProcessIndex] = self.strProcessStateTerminated - #time.sleep(10) - pass - - #todo fixhere 放到公用类里去 - def stockListSeperateToListCount(self, taskNumber, stockCounts): - # for i in stock_list_length: - - counts_list = [] - if stockCounts % taskNumber == 0: - subBlockCount = stockCounts // taskNumber - for i in range(taskNumber): - counts_list.append(subBlockCount) - return counts_list - - taskNumberPlusOne = taskNumber + 1 - - subsotck_list_length = stockCounts // taskNumberPlusOne - substock_list_remain = stockCounts % taskNumberPlusOne - - subRemainDivion = (subsotck_list_length + substock_list_remain) // taskNumber - subRemainRemain = (subsotck_list_length + substock_list_remain) % taskNumber - - eachBlockSize = subsotck_list_length + subRemainDivion - lastBlockSize = eachBlockSize + subRemainRemain - - - for i in range(taskNumber-1): - counts_list.append(eachBlockSize) - counts_list.append(lastBlockSize) - - return counts_list - - #todo fixhere 放到公用类里去 - ''' - to list in list - ''' - def stockListSeperatorToListList(self, stockAllList, stockSegCountList): - lastSubCount = 0 - iSegmentIndex = 0 - - subSegCodelistInlist = [] - for iSegmentCount in stockSegCountList: - subCodeList = [] - for iCountSub in range(iSegmentCount): - subCodeList.append(stockAllList[iCountSub + lastSubCount]) - lastSubCount = lastSubCount + stockSegCountList[iSegmentIndex] - subSegCodelistInlist.append(subCodeList) - iSegmentIndex = iSegmentIndex + 1 - - return subSegCodelistInlist - - ''' - - ''' - - #todo fixhere 放到公用类里去 - def assignStockListSegment(self, parentWnd): - - self.currentNeedUpdateStockCodeList.clear() - self.cuurentNeedUpdateCodeSegmentCountLists.clear() - self.currentNeedUpdateCodeSegemenStockList.clear() - - workThreading = QThread_GetStockList_Partition() - - mongo_uri = QASETTING.mongo_uri - strMsgTitle = "🔬 尝试连接数据库 🗃" - strMsg = "📂 正在获取股票列表 📚 {}".format(mongo_uri) - dlg = ProgressDlg_WithQThread(parentWnd,workThreading,strMsg,strMsgTitle) - dlg.startMyThread() - dlg.exec() - - - workThreading_for_check_check_zjlx_db = QThread_Check_ZJLX_DB_Status() - workThreading_for_check_check_zjlx_db.pyqtSignalToLogTable = parentWnd.trigger_table_log_zjlx_db_status - workThreading_for_check_check_zjlx_db.zjlxRecNeedUpdateStockCodes.clear() - - strMsgTitle = "🔬 检查资金流向数据库中的 记录 🗃" - strMsg = "📂 正在读取资金资金流向数据库 📚 {}".format(mongo_uri) - dlg = ProgressDlg_WithQThread(parent= parentWnd, - qThreadObj=workThreading_for_check_check_zjlx_db, - userHint=strMsg, dlgTitle=strMsgTitle) - dlg.startMyThread() - dlg.exec() - - needStockCount = len(workThreading_for_check_check_zjlx_db.zjlxRecNeedUpdateStockCodes) - codeCountsList = self.stockListSeperateToListCount(processNumber, needStockCount) - - - strMsg1 = "需要获取 A股 {} 个股票最近100天资金流向 \n".format(needStockCount) - iCount = 0 - for iSubBlockCount in codeCountsList: - strMsg1 = strMsg1 + "进程#{} 分配股票个数 {} \n".format(iCount,iSubBlockCount) - iCount=iCount+1 - - dlg = QMessageBox.information(parentWnd,"分配股票每个股票区间个数", strMsg1) - - self.currentNeedUpdateStockCodeList = workThreading_for_check_check_zjlx_db.zjlxRecNeedUpdateStockCodes - self.cuurentNeedUpdateCodeSegmentCountLists = codeCountsList - - self.currentNeedUpdateCodeSegemenStockList = self.stockListSeperatorToListList( - self.currentNeedUpdateStockCodeList, self.cuurentNeedUpdateCodeSegmentCountLists - ) - - - try: - iProIndex = 0 - for row in self.currentNeedUpdateCodeSegemenStockList: - trigger = parentWnd.trigger_sub_process_label_by_index(iProIndex) - strTxt = '🐌%d进程,没有分配代码段:[%s~%s],进度:0/%d,操作日志'% (iProIndex, row[0], row[len(row)-1],len(row)) - - #strTxt = '🐌%d进程,分配代码段:[%s~%s],进度:0/%d,没有开始' % (iProIndex, row[0], row[len(row)-1],len(row)) - trigger.emit(strTxt) - iProIndex = iProIndex+1 - except Exception as ee: - print(ee) - - #check point 置0 - for i in range(processNumber): - self.lastTimeProgressCheckPoint[i] = 0 - - pass - - ######################################################################################################### - - def getCurrentProcessState(self, iProcessIndex): - return self.strCurrentProcessState[iProcessIndex] - - - def getCurrentThreadState(self, iProcessIndex): - return self.strCurrentThreadState[iProcessIndex] - - ######################################################################################################### - - def cmdProcessDoTheJob(self,parentWnd, iProcessIndex, connectAddress, connectPortInt): - - if self.currentNeedUpdateCodeSegemenStockList[iProcessIndex] is None or len(self.currentNeedUpdateCodeSegemenStockList[iProcessIndex]) == 0: - msg = QMessageBox() - msg.setIcon(QMessageBox.Information) - msg.setText(" 🅾️ 没有分配到股票! 🅾️ ") - msg.setInformativeText(" 🅾️ 没有分配到股票 🅾️ ") - msg.setWindowTitle("操作提示:") - msg.setDetailedText(" 🅾️ 没有分配到股票 🅾️ ") - retval = msg.exec() - return - - - if self.strCurrentProcessState[iProcessIndex] == self.strProcessStateRunning: - - if self.strCurrentThreadState[iProcessIndex] == self.strThreadStateTerminated: - - workThreading = QThread_Fetch_Eastmoney_WebPageData() - - #初始化线程 变量, 从 QT 继承的类 没有 init ??? - self.threadList[iProcessIndex] = workThreading - workThreading.stockCodeList = self.currentNeedUpdateCodeSegemenStockList[iProcessIndex] - workThreading.connectAddress = connectAddress - workThreading.connectPortInt = connectPortInt - workThreading.processIndex= iProcessIndex - workThreading.pyqtSignalToLogErrorTable = parentWnd.trigger_table_error_log - workThreading.pyqtSignalToLogOpInfoTable = parentWnd.trigger_table_process_thread_op_log - - workThreading.lastTimeCheckPointStart = self.lastTimeProgressCheckPoint[iProcessIndex] - - workThreading.start() - self.strCurrentThreadState[iProcessIndex] = self.strThreadStateRunning - self.threadList[iProcessIndex] = workThreading - - msg = QMessageBox() - msg.setIcon(QMessageBox.Information) - msg.setText("🌀线程已经启动成功!👻 ") - msg.setInformativeText("🌀线程已经启动成功👻 ") - msg.setWindowTitle("操作提示:") - msg.setDetailedText("🌀线程已经启动成功") - retval = msg.exec() - else: - - msg = QMessageBox() - msg.setIcon(QMessageBox.Information) - msg.setText(" 🅾️ 线程已经启动!🅾️ ") - msg.setInformativeText("🅾️ 线程已经启动 🅾️ ") - msg.setWindowTitle("操作提示:") - msg.setDetailedText("🅾️ 线程已经启动 🅾️ ") - retval = msg.exec() - else: - - msg = QMessageBox() - msg.setIcon(QMessageBox.Information) - msg.setText(" 🅾️ 进程没有启动!🅾️ ") - msg.setInformativeText("🅾️ 进程没有启动 🅾️") - msg.setWindowTitle("操作提示:") - msg.setDetailedText("进程没有启动") - retval = msg.exec() - - - def cmdProcessStopTheJob(self,parentWnd, iProcessIndex, connectAddress, connectPortInt): - - - if self.strCurrentThreadState[iProcessIndex] == self.strThreadStateRunning: - - workThreading = self.threadList[iProcessIndex] - workThreading.bThreadTobeOver = True - - dlg = ProgressDlg_Timeout(None, 10, '🌀等待线程已经成功结束!💀 ') - dlg.exec() - - while True: - if workThreading.isFinished() == True: - break - - - self.strCurrentThreadState[iProcessIndex] = self.strThreadStateTerminated - - - msg = QMessageBox() - msg.setIcon(QMessageBox.Information) - msg.setText("🌀线程已经成功结束!💀 ") - msg.setInformativeText("🌀线程已经成功结束 💀 ") - msg.setWindowTitle("操作提示:") - msg.setDetailedText("🌀线程已经成功结束 💀 ") - retval = msg.exec() - - else: - msg = QMessageBox() - msg.setIcon(QMessageBox.Information) - msg.setText(" 🅾️ 线程没有启动! 🅾️ ") - msg.setInformativeText("线程没有启动 🅾️ ") - msg.setWindowTitle("操作提示:") - msg.setDetailedText(" 🅾️ 线程没有启动 🅾️ ") - retval = msg.exec() - - - def addSuccessCodeToCheckPoint(self,strProcessIndex): - - iProcesIndex = int(strProcessIndex) - self.lastTimeProgressCheckPoint[iProcesIndex] = self.lastTimeProgressCheckPoint[iProcesIndex] + 1 - - print("%d 保存记录点!%d",iProcesIndex, self.lastTimeProgressCheckPoint[iProcesIndex]) - pass - - def getSuccessCodeCheckPointCount(self, strProcessIndex): - iProcesIndex = int(strProcessIndex) - return self.lastTimeProgressCheckPoint[iProcesIndex] - - - def updateCurrentProcessThreadStatus(self, parentWnd : 'TabEastMoneyZJLX'): - - - - for iIndex in range(processNumber): - - #self.processList[iIndex] - if self.threadList[iIndex] is not None and self.threadList[iIndex].isFinished(): - self.strCurrentThreadState[iIndex] = self.strThreadStateTerminated - - if self.strCurrentProcessState[iIndex] == self.strProcessStateRunning: - strStatesLabel = "#%d ✅进程运行中✅ "%(iIndex) - - if self.strCurrentThreadState[iIndex] == self.strThreadStateRunning: - strStatesLabel = strStatesLabel + "#%d ✅线程运行中✅ "%(iIndex) - else: - strStatesLabel = strStatesLabel + "#%d ⛔💤️线程未运行💤⛔ "%(iIndex) - - - else: - strStatesLabel = "#%d ⛔💤进程未运行💤⛔ "%iIndex - - parentWnd.lstSubProcessOpMsg[iIndex].setText(strStatesLabel) - - - pass diff --git a/QUANTAXIS_Monitor_GUI/MainTabWindows/Tab00_WelcomeSplash.py b/QUANTAXIS_Monitor_GUI/MainTabWindows/Tab00_WelcomeSplash.py deleted file mode 100644 index 816e4643d..000000000 --- a/QUANTAXIS_Monitor_GUI/MainTabWindows/Tab00_WelcomeSplash.py +++ /dev/null @@ -1,57 +0,0 @@ - -import sys -import os - -from PyQt5.QtCore import * -from PyQt5.QtGui import * -from PyQt5.QtWidgets import * - -#http://www.widlabs.com/article/no-module-named-pyqt5-qtwebkitwidgets -#from PyQt5.QtWebKitWidgets import * -from PyQt5.QtWebEngineWidgets import QWebEnginePage, QWebEngineView - -from QUANTAXIS_Monitor_GUI.MainTabWindows.Tab0_RootClass import * - - -class TabWelcomeSplash(TabRootClass): - def __init__(self, parent=None): - super(TabWelcomeSplash, self).__init__(parent) - - - def initUI(self): - # self.setWindowOpacity(1) - # self.setWindowFlags(Qt.FramelessWindowHint) - # self.setAttribute(Qt.WA_TranslucentBackground) - # self.showFullScreen() - rect = QApplication.desktop().screenGeometry() - self.resize(rect.width(), rect.height()) - self.setWindowFlags(Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint) - - self.webview = QWebEngineView() - - vbox = QVBoxLayout() - vbox.addWidget(self.webview) - - main = QGridLayout() - main.setSpacing(0) - main.addLayout(vbox, 0, 0) - - self.setLayout(main) - - #dirname, filename = os.path.split(os.path.abspath(__file__)) - # dir = os.getcwd(); # - - realPath = os.path.realpath(__file__) - realDir = os.path.dirname(realPath); - realHtml = realDir + "/splash_html_page/splash.html" - realUrl = "file:///"+ realHtml; - - #self.webview.load(QUrl("file:////Users/jerryw/MyCode/QUANTAXIS/QUANTAXIS_Monitor_GUI/MainTabWindows/splash_html_page/splash.html")) - self.webview.load(QUrl(realUrl)) - - self.webview.setContextMenuPolicy(Qt.NoContextMenu) - self.webview.show() - # self.setWindowTitle("CoDataHD") - # webview.load(QUrl('http://www.cnblogs.com/misoag/archive/2013/01/09/2853515.html')) - # webview.show() - diff --git a/QUANTAXIS_Monitor_GUI/MainTabWindows/Tab01_DataMaintenance.py b/QUANTAXIS_Monitor_GUI/MainTabWindows/Tab01_DataMaintenance.py deleted file mode 100644 index 6ea7383e0..000000000 --- a/QUANTAXIS_Monitor_GUI/MainTabWindows/Tab01_DataMaintenance.py +++ /dev/null @@ -1,552 +0,0 @@ -import sys - -from QUANTAXIS_Monitor_GUI.TasksByThreading.QA_Gui_DateFetch_Task import * - -#https://www.cnblogs.com/gaigaige/p/7883713.html 改改哥 -class EmittingStream(QtCore.QObject): - textWritten = QtCore.pyqtSignal(str) # 定义一个发送str的信号 - - def write(self, text): - self.textWritten.emit(str(text)) - - -class TabDataMaintenance(QWidget): - def __init__(self, parent=None): - super(TabDataMaintenance, self).__init__(parent) - - def initUI(self): - ''' - |--------------|------------| - | | | - | | | - |task list1 | log display| - |task list1 | | - |task list1 | | - |task list1 | | - |------------- |------------| - | button | - |---------------------------| - :return: - ''' - - self.setWindowIconText("获取数据任务列表") - self.setObjectName("data_maintenance") - QtCore.QMetaObject.connectSlotsByName(self) - - # 下面将输出重定向到textEdit中 - sys.stdout = EmittingStream(textWritten=self.outputWritten) - sys.stderr = EmittingStream(textWritten=self.outputWritten) - - - # 🛠todo 日志显示,用table view list 加入搜索的功能, 行号等, 彩色显示, - self.logDisplay = QTableWidget(self) - - self.logDisplay.setObjectName("tableForLog") - # self.logDisplay.setEnabled(False) - #self.logDisplay.set(True) - #self.logDisplay.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOn) - self.logDisplay.setColumnCount(2); - self.logDisplay.setHorizontalHeaderLabels(['日志内容','来源']) - self.logDisplay.setColumnWidth(0,700) - self.logDisplay.setColumnWidth(1,100) - - - #https://stackoverflow.com/questions/47910192/pyqt-qgridlayout-different-column-width - self.gridLayut = QGridLayout() - self.taskListLayout = QVBoxLayout() - self.logListLayout = QVBoxLayout() - self.buttonListLayout = QHBoxLayout() - - self.gridLayut.addLayout(self.taskListLayout, 0,0, 1,1) - self.gridLayut.addLayout(self.logListLayout , 0,1, 1,1) - - self.gridLayut.setColumnMinimumWidth(1,1400) - ''' - void QGridLayout::addLayout(QLayout *layout, int row, int column, int rowSpan, int columnSpan, Qt::Alignment alignment = Qt::Alignment()) - This is an overloaded function. - This version adds the layout layout to the cell grid, spanning multiple rows/columns. - The cell will start at row, column spanning rowSpan rows and columnSpan columns. - If rowSpan and/or columnSpan is -1, then the layout will extend to the bottom and/or right edge, respectively. - ''' - self.gridLayut.addLayout(self.buttonListLayout, 1,0,1,3) - - - #🛠todo QT 报错 QWidget::setLayout: Attempting to set QLayout "" on QWidget "", which already has a layout - self.setLayout(self.gridLayut) - - self.qCheckboxWidgetList = [] - self.qProgressWidgetList = [] - self.allSubJobList = [] - - # 🛠todo this is really stupid 01 02 03 04,... should use template ? does python have some template feature like c++ - ################################################################################################## - self.create_job_08_save_stock_list() - ################################################################################################## - self.create_job_09_save_stock_block() - ################################################################################################## - self.create_job_10_save_stock_info() - ################################################################################################## - ################################################################################################## - self.create_job_01_save_stock_day() - ################################################################################################## - #self.create_job01_save_stock_week() - ################################################################################################## - #self.create_job01_save_stock_month() - ################################################################################################## - #self.create_job_01_save_stock_year() - ################################################################################################## - self.create_job_02_save_stock_xdxr() - ################################################################################################## - self.create_job_03_save_stock_min() - ################################################################################################## - self.create_job_04_save_index_day() - ################################################################################################## - self.create_job_05_save_index_min() - ################################################################################################## - self.create_job_06_save_etf_day() - ################################################################################################## - self.create_job_07_save_etf_min() - ################################################################################################## - #self.create_job_11_save_stock_transaction() - ################################################################################################## - self.create_job_12_save_option_day() - ################################################################################################## - - self.selectedSubTask = QA_GUI_Selected_TaskQueue(self.logDisplay) - self.selectedSubTask.trigger_all_task_start.connect(self.uiAllTaskStart) - self.selectedSubTask.trigger_all_task_done.connect(self.uiAllTaskDone) - - ################################################################################################## - - self.logListLayout.addWidget(self.logDisplay) - - self.bntExecute = QPushButton(self) - self.bntExecute.setText("执行选中的任务 🐌") - self.buttonListLayout.addWidget(self.bntExecute) - - # 🛠todo 没有实现! - self.bntStopTack = QPushButton(self) - self.bntStopTack.setText("停止执行任务 🚫") - self.buttonListLayout.addWidget(self.bntStopTack) - - self.bntClearLog = QPushButton(self) - self.bntClearLog.setText("清除日志 🗑") - self.buttonListLayout.addWidget(self.bntClearLog) - - self.bntExecute.clicked.connect(self.doSelectedTask) - self.bntStopTack.clicked.connect(self.doStopTask) - - # layout = QFormLayout() - # layout.setLabelAlignment(Qt.AlignLeft) - # layout.addRow("保存日线数据 ", QProgressBar(self)) - # layout.addRow("保存日除权出息数据 ", QProgressBar(self)) - # layout.addRow("保存分钟线数据", QProgressBar(self)) - # layout.addRow("保存指数数据", QProgressBar(self)) - # - # layout.addRow("保存指数线数据 ", QProgressBar(self)) - # layout.addRow("保存ETF日线数据 ", QProgressBar(self)) - # layout.addRow("保存ET分钟数据", QProgressBar(self)) - # layout.addRow("保存股票列表", QProgressBar(self)) - # layout.addRow("保存板块", QProgressBar(self)) - # layout.addRow("保存tushare数据接口获取的股票列表", QProgressBar(self)) - # layout.addRow("保存高级财务数据(自1996年开始)", QProgressBar(self)) - # layout.addRow("保存50ETF期权日线数据(不包括已经摘牌的数据)", QProgressBar(self)) - # - # qPushBnt = QPushButton(self); - # qPushBnt.setText("开始执行") - # layout.addRow("选中需要执行的任务", qPushBnt) - - # 为这个tab命名显示出来,第一个参数是哪个标签,第二个参数是标签的名字 - # 在标签1中添加这个帧布局 - - def outputWritten(self, text): - # 🛠todo logDisplay QTableWidget - #cursor = self.logDisplay.textCursor() - # cursor.movePosition(QtGui.QTextCursor.End) - # cursor.insertText(text) - # self.logDisplay.setTextCursor(cursor) - # self.logDisplay.ensureCursorVisible() - if text and text.strip(): - rowCount = self.logDisplay.rowCount() - newItem1 = QTableWidgetItem(text) - newItem2 = QTableWidgetItem("stdout/stderr") - - self.logDisplay.setRowCount(rowCount+1) - self.logDisplay.setItem(rowCount,0,newItem1) - self.logDisplay.setItem(rowCount,1,newItem2) - self.logDisplay.scrollToBottom() - - ################################################################################################## - - def create_job_01_save_stock_day(self): - # 🛠todo 继承QWidget , 写一个类, 里面有 进度条, checkbox ,和绑定到线程 - self.qCheckBoxJob01_save_stock_day = QCheckBox(self); - self.qCheckBoxJob01_save_stock_day.setText("JOB01 日线数据 📊") - self.qProgressJob01_save_stock_day = QProgressBar(self); - self.qProgressJob01_save_stock_day.setMaximum(100) - # 🛠todo 应该有更加好的实现方式, 把progress bar 绑定到 任务对象中,这样写实在是太粗糙了。 - # 把job 对象 绑定到界面中 , 继承 QCheckBox 把相关到对象线程 和 widget 绑定。 - self.job01_save_stock_day = QA_GUI_DateFetch_SU_job01_stock_day() - - self.job01_save_stock_day.setLoggingUIWidget(self.logDisplay) - self.job01_save_stock_day.setProgressUIWidget(self.qProgressJob01_save_stock_day) - self.job01_save_stock_day.setCheckboxUIWidget(self.qCheckBoxJob01_save_stock_day) - - self.job01_save_stock_day.connectSignalSlot(); - - # 🛠todo 进一步封装 hardcode 1 2 3 不是一种好的的做法 - self.qCheckboxWidgetList.append(self.qCheckBoxJob01_save_stock_day) - self.qProgressWidgetList.append(self.qProgressJob01_save_stock_day) - self.allSubJobList.append(self.job01_save_stock_day) - # 🛠todo 进一步封装 hardcode 1 2 3 不是一种好的的做法 - self.taskListLayout.addWidget(self.qCheckBoxJob01_save_stock_day) - self.taskListLayout.addWidget(self.qProgressJob01_save_stock_day) - - ################################################################################################## - def create_job01_save_stock_week(self): - self.qCheckBoxJob01_save_stock_week = QCheckBox(self); - self.qCheckBoxJob01_save_stock_week.setText("JOB01 周线数据 📊") - self.qProgressJob01_save_stock_week = QProgressBar(self) - self.qProgressJob01_save_stock_week.setMaximum(100) - - # 🛠todo 不知道为何,QThread 继承的 都不执行 __init__ - self.job01_save_stock_week = QA_GUI_DateFetch_SU_job01_stock_week() - - self.job01_save_stock_week.setLoggingUIWidget(self.logDisplay) - self.job01_save_stock_week.setProgressUIWidget(self.qProgressJob01_save_stock_week) - self.job01_save_stock_week.setCheckboxUIWidget(self.qCheckBoxJob01_save_stock_week) - - self.job01_save_stock_week.connectSignalSlot(); - - self.qCheckboxWidgetList.append(self.qCheckBoxJob01_save_stock_week) - self.qProgressWidgetList.append(self.qProgressJob01_save_stock_week) - self.allSubJobList.append(self.job01_save_stock_week) - self.taskListLayout.addWidget(self.qCheckBoxJob01_save_stock_week) - self.taskListLayout.addWidget(self.qProgressJob01_save_stock_week) - - ################################################################################################## - def create_job01_save_stock_month(self): - - self.qCheckBoxJob01_save_stock_month = QCheckBox(self) - self.qCheckBoxJob01_save_stock_month.setText("JOB01 月线数据 📊") - self.qProgressJob01_save_stock_month = QProgressBar(self) - self.qProgressJob01_save_stock_month.setMaximum(100) - - self.job01_save_stock_month = QA_GUI_DateFetch_SU_job01_stock_month() - - self.job01_save_stock_month.setLoggingUIWidget(self.logDisplay) - self.job01_save_stock_month.setProgressUIWidget(self.qProgressJob01_save_stock_month) - self.job01_save_stock_month.setCheckboxUIWidget(self.qCheckBoxJob01_save_stock_month) - - self.job01_save_stock_month.connectSignalSlot(); - - self.qCheckboxWidgetList.append(self.qCheckBoxJob01_save_stock_month) - self.qProgressWidgetList.append(self.qProgressJob01_save_stock_month) - self.allSubJobList.append(self.job01_save_stock_month) - self.taskListLayout.addWidget(self.qCheckBoxJob01_save_stock_month) - self.taskListLayout.addWidget(self.qProgressJob01_save_stock_month) - - ################################################################################################## - def create_job_01_save_stock_year(self): - self.qCheckBoxJob01_save_stock_year = QCheckBox(self) - self.qCheckBoxJob01_save_stock_year.setText("JOB01 年线数据 📊") - self.qProgressJob01_save_stock_year = QProgressBar(self) - self.qProgressJob01_save_stock_year.setMaximum(100) - - self.job01_save_stock_year = QA_GUI_DateFetch_SU_job01_stock_year() - - self.job01_save_stock_year.setLoggingUIWidget(self.logDisplay) - self.job01_save_stock_year.setProgressUIWidget(self.qProgressJob01_save_stock_year) - self.job01_save_stock_year.setCheckboxUIWidget(self.qCheckBoxJob01_save_stock_year) - - self.job01_save_stock_year.connectSignalSlot(); - - self.qCheckboxWidgetList.append(self.qCheckBoxJob01_save_stock_year) - self.qProgressWidgetList.append(self.qProgressJob01_save_stock_year) - self.allSubJobList.append(self.job01_save_stock_year) - self.taskListLayout.addWidget(self.qCheckBoxJob01_save_stock_year) - self.taskListLayout.addWidget(self.qProgressJob01_save_stock_year) - - ################################################################################################## - def create_job_02_save_stock_xdxr(self): - self.qCheckBoxJob02_save_stock_xdxr = QCheckBox(self) - self.qCheckBoxJob02_save_stock_xdxr.setText("JOB02 除权除息数据 📊") - self.qProgressJob02_save_stock_xdxr = QProgressBar(self) - self.qProgressJob02_save_stock_xdxr.setMaximum(100) - - self.job02_save_stock_xdxr = QA_GUI_DateFetch_SU_job02_stock_xdxr() - - self.job02_save_stock_xdxr.setLoggingUIWidget(self.logDisplay) - self.job02_save_stock_xdxr.setProgressUIWidget(self.qProgressJob02_save_stock_xdxr) - self.job02_save_stock_xdxr.setCheckboxUIWidget(self.qCheckBoxJob02_save_stock_xdxr) - - self.job02_save_stock_xdxr.connectSignalSlot(); - - self.qCheckboxWidgetList.append(self.qCheckBoxJob02_save_stock_xdxr) - self.qProgressWidgetList.append(self.qProgressJob02_save_stock_xdxr) - self.allSubJobList.append(self.job02_save_stock_xdxr) - self.taskListLayout.addWidget(self.qCheckBoxJob02_save_stock_xdxr) - self.taskListLayout.addWidget(self.qProgressJob02_save_stock_xdxr) - - ################################################################################################## - - def create_job_03_save_stock_min(self): - self.qCheckBoxJob03_save_stock_min = QCheckBox(self) - self.qCheckBoxJob03_save_stock_min.setText("JOB03 分钟数据 📊") - self.qProgressJob03_save_stock_min = QProgressBar(self) - self.qProgressJob03_save_stock_min.setMaximum(10000) # 最小变动单位 0.01 - - self.job03_save_stock_min = QA_GUI_DateFetch_SU_job03_stock_min() - - self.job03_save_stock_min.setLoggingUIWidget(self.logDisplay) - self.job03_save_stock_min.setProgressUIWidget(self.qProgressJob03_save_stock_min) - self.job03_save_stock_min.setCheckboxUIWidget(self.qCheckBoxJob03_save_stock_min) - - self.job03_save_stock_min.connectSignalSlot(); - - self.qCheckboxWidgetList.append(self.qCheckBoxJob03_save_stock_min) - self.qProgressWidgetList.append(self.qProgressJob03_save_stock_min) - self.allSubJobList.append(self.job03_save_stock_min) - self.taskListLayout.addWidget(self.qCheckBoxJob03_save_stock_min) - self.taskListLayout.addWidget(self.qProgressJob03_save_stock_min) - - ################################################################################################## - - def create_job_04_save_index_day(self): - self.qCheckBoxJob04_save_index_day = QCheckBox(self) - self.qCheckBoxJob04_save_index_day.setText("JOB04 指数日线数据 📊") - self.qProgressJob04_save_index_day = QProgressBar(self) - self.qProgressJob04_save_index_day.setMaximum(10000) # 最小变动单位 0.01 - - self.job04_save_index_day = QA_GUI_DateFetch_SU_job04_index_day() - - self.job04_save_index_day.setLoggingUIWidget(self.logDisplay) - self.job04_save_index_day.setProgressUIWidget(self.qProgressJob04_save_index_day) - self.job04_save_index_day.setCheckboxUIWidget(self.qCheckBoxJob04_save_index_day) - - self.job04_save_index_day.connectSignalSlot(); - - self.qCheckboxWidgetList.append(self.qCheckBoxJob04_save_index_day) - self.qProgressWidgetList.append(self.qProgressJob04_save_index_day) - self.allSubJobList.append(self.job04_save_index_day) - self.taskListLayout.addWidget(self.qCheckBoxJob04_save_index_day) - self.taskListLayout.addWidget(self.qProgressJob04_save_index_day) - - ################################################################################################## - - def create_job_05_save_index_min(self): - self.qCheckBoxJob05_save_index_min = QCheckBox(self) - self.qCheckBoxJob05_save_index_min.setText("JOB05 指数分钟数据 📊") - self.qProgressJob05_save_index_min = QProgressBar(self) - self.qProgressJob05_save_index_min.setMaximum(10000) # 最小变动单位 0.01 - - self.job05_save_index_min = QA_GUI_DateFetch_SU_job05_index_min() - - self.job05_save_index_min.setLoggingUIWidget(self.logDisplay) - self.job05_save_index_min.setProgressUIWidget(self.qProgressJob05_save_index_min) - self.job05_save_index_min.setCheckboxUIWidget(self.qCheckBoxJob05_save_index_min) - - self.job05_save_index_min.connectSignalSlot(); - - self.qCheckboxWidgetList.append(self.qCheckBoxJob05_save_index_min) - self.qProgressWidgetList.append(self.qProgressJob05_save_index_min) - self.allSubJobList.append(self.job05_save_index_min) - self.taskListLayout.addWidget(self.qCheckBoxJob05_save_index_min) - self.taskListLayout.addWidget(self.qProgressJob05_save_index_min) - - ################################################################################################## - - def create_job_06_save_etf_day(self): - self.qCheckBoxJob06_save_etf_day = QCheckBox(self) - self.qCheckBoxJob06_save_etf_day.setText("JOB06 ETF日线数据 📊") - self.qProgressJob06_save_etf_day = QProgressBar(self) - self.qProgressJob06_save_etf_day.setMaximum(10000) # 最小变动单位 0.01 - - self.job06_save_etf_day = QA_GUI_DateFetch_SU_job06_etf_day() - - self.job06_save_etf_day.setLoggingUIWidget(self.logDisplay) - self.job06_save_etf_day.setProgressUIWidget(self.qProgressJob06_save_etf_day) - self.job06_save_etf_day.setCheckboxUIWidget(self.qCheckBoxJob06_save_etf_day) - - self.job06_save_etf_day.connectSignalSlot(); - - self.qCheckboxWidgetList.append(self.qCheckBoxJob06_save_etf_day) - self.qProgressWidgetList.append(self.qProgressJob06_save_etf_day) - self.allSubJobList.append(self.job06_save_etf_day) - self.taskListLayout.addWidget(self.qCheckBoxJob06_save_etf_day) - self.taskListLayout.addWidget(self.qProgressJob06_save_etf_day) - - ################################################################################################## - - def create_job_07_save_etf_min(self): - self.qCheckBoxJob07_save_etf_min = QCheckBox(self) - self.qCheckBoxJob07_save_etf_min.setText("JOB07 ETF分钟数据 📊") - self.qProgressJob07_save_etf_min = QProgressBar(self) - self.qProgressJob07_save_etf_min.setMaximum(10000) # 最小变动单位 0.01 - - self.job07_save_etf_min = QA_GUI_DateFetch_SU_job07_etf_min() - - self.job07_save_etf_min.setLoggingUIWidget(self.logDisplay) - self.job07_save_etf_min.setProgressUIWidget(self.qProgressJob07_save_etf_min) - self.job07_save_etf_min.setCheckboxUIWidget(self.qCheckBoxJob07_save_etf_min) - - self.job07_save_etf_min.connectSignalSlot(); - - self.qCheckboxWidgetList.append(self.qCheckBoxJob07_save_etf_min) - self.qProgressWidgetList.append(self.qProgressJob07_save_etf_min) - self.allSubJobList.append(self.job07_save_etf_min) - self.taskListLayout.addWidget(self.qCheckBoxJob07_save_etf_min) - self.taskListLayout.addWidget(self.qProgressJob07_save_etf_min) - - ################################################################################################## - - def create_job_08_save_stock_list(self): - self.qCheckBoxJob08_save_stock_list = QCheckBox(self) - self.qCheckBoxJob08_save_stock_list.setText("JOB08 股票列表 📊") - self.qProgressJob08_save_stock_list = QProgressBar(self) - self.qProgressJob08_save_stock_list.setMaximum(10000) # 最小变动单位 0.01 - - self.job08_save_stock_list = QA_GUI_DateFetch_SU_job08_stock_list() - - self.job08_save_stock_list.setLoggingUIWidget(self.logDisplay) - self.job08_save_stock_list.setProgressUIWidget(self.qProgressJob08_save_stock_list) - self.job08_save_stock_list.setCheckboxUIWidget(self.qCheckBoxJob08_save_stock_list) - - self.job08_save_stock_list.connectSignalSlot(); - - self.qCheckboxWidgetList.append(self.qCheckBoxJob08_save_stock_list) - self.qProgressWidgetList.append(self.qProgressJob08_save_stock_list) - self.allSubJobList.append(self.job08_save_stock_list) - self.taskListLayout.addWidget(self.qCheckBoxJob08_save_stock_list) - self.taskListLayout.addWidget(self.qProgressJob08_save_stock_list) - - ################################################################################################## - - def create_job_09_save_stock_block(self): - self.qCheckBoxJob09_save_stock_block = QCheckBox(self) - self.qCheckBoxJob09_save_stock_block.setText("JOB08 股票板块数据 📊") - self.qProgressJob09_save_stock_block = QProgressBar(self) - self.qProgressJob09_save_stock_block.setMaximum(10000) # 最小变动单位 0.01 - - self.job09_save_stock_block = QA_GUI_DateFetch_SU_job09_stock_block() - - self.job09_save_stock_block.setLoggingUIWidget(self.logDisplay) - self.job09_save_stock_block.setProgressUIWidget(self.qProgressJob09_save_stock_block) - self.job09_save_stock_block.setCheckboxUIWidget(self.qCheckBoxJob09_save_stock_block) - - self.job09_save_stock_block.connectSignalSlot(); - - self.qCheckboxWidgetList.append(self.qCheckBoxJob09_save_stock_block) - self.qProgressWidgetList.append(self.qProgressJob09_save_stock_block) - self.allSubJobList.append(self.job09_save_stock_block) - self.taskListLayout.addWidget(self.qCheckBoxJob09_save_stock_block) - self.taskListLayout.addWidget(self.qProgressJob09_save_stock_block) - - ################################################################################################## - def create_job_10_save_stock_info(self): - self.qCheckBoxJob10_save_stock_info = QCheckBox(self) - self.qCheckBoxJob10_save_stock_info.setText("JOB10 股票基本数据 📊") - self.qProgressJob10_save_stock_info = QProgressBar(self) - self.qProgressJob10_save_stock_info.setMaximum(10000) # 最小变动单位 0.01 - - self.job10_save_stock_info = QA_GUI_DateFetch_SU_job10_stock_info() - - self.job10_save_stock_info.setLoggingUIWidget(self.logDisplay) - self.job10_save_stock_info.setProgressUIWidget(self.qProgressJob10_save_stock_info) - self.job10_save_stock_info.setCheckboxUIWidget(self.qCheckBoxJob10_save_stock_info) - - self.job10_save_stock_info.connectSignalSlot(); - - self.qCheckboxWidgetList.append(self.qCheckBoxJob10_save_stock_info) - self.qProgressWidgetList.append(self.qProgressJob10_save_stock_info) - self.allSubJobList.append(self.job10_save_stock_info) - self.taskListLayout.addWidget(self.qCheckBoxJob10_save_stock_info) - self.taskListLayout.addWidget(self.qProgressJob10_save_stock_info) - - def create_job_11_save_stock_transaction(self): - - self.qCheckBoxJob11_save_stock_transaction = QCheckBox(self) - self.qCheckBoxJob11_save_stock_transaction.setText("JOB11 股票3秒的tick数据 📊") - self.qProgressJob11_save_stock_transaction = QProgressBar(self) - self.qProgressJob11_save_stock_transaction.setMaximum(10000) # 最小变动单位 0.01 - - self.job11_save_stock_transaction = QA_GUI_DateFetch_SU_job11_stock_transaction() - - self.job11_save_stock_transaction.setLoggingUIWidget(self.logDisplay) - self.job11_save_stock_transaction.setProgressUIWidget(self.qProgressJob11_save_stock_transaction) - self.job11_save_stock_transaction.setCheckboxUIWidget(self.qCheckBoxJob11_save_stock_transaction) - - self.job11_save_stock_transaction.connectSignalSlot(); - - self.qCheckboxWidgetList.append(self.qCheckBoxJob11_save_stock_transaction) - self.qProgressWidgetList.append(self.qProgressJob11_save_stock_transaction) - self.allSubJobList.append(self.job11_save_stock_transaction) - self.taskListLayout.addWidget(self.qCheckBoxJob11_save_stock_transaction) - self.taskListLayout.addWidget(self.qProgressJob11_save_stock_transaction) - - def create_job_12_save_option_day(self): - - self.qCheckBoxJob12_save_option_day = QCheckBox(self) - self.qCheckBoxJob12_save_option_day.setText("JOB12 50ETF期权日线数据 📊") - self.qProgressJob12_save_option_day = QProgressBar(self) - self.qProgressJob12_save_option_day.setMaximum(10000) # 最小变动单位 0.01 - - self.job12_save_option_day = QA_GUI_DateFetch_SU_job12_option_day() - - self.job12_save_option_day.setLoggingUIWidget(self.logDisplay) - self.job12_save_option_day.setProgressUIWidget(self.qProgressJob12_save_option_day) - self.job12_save_option_day.setCheckboxUIWidget(self.qCheckBoxJob12_save_option_day) - - self.job12_save_option_day.connectSignalSlot(); - - self.qCheckboxWidgetList.append(self.qCheckBoxJob12_save_option_day) - self.qProgressWidgetList.append(self.qProgressJob12_save_option_day) - self.allSubJobList.append(self.job12_save_option_day) - self.taskListLayout.addWidget(self.qCheckBoxJob12_save_option_day) - self.taskListLayout.addWidget(self.qProgressJob12_save_option_day) - - def doSelectedTask(self): - #print("^ 准备执行选中的任务 ^") - - self.selectedSubTask.clearTask() - - # 🛠todo 需要一个总的线程队列按顺序执行 每个任务 - for itaskIndex in range(len(self.qCheckboxWidgetList)): - if self.qCheckboxWidgetList[itaskIndex].isChecked(): - self.selectedSubTask.putTask(self.allSubJobList[itaskIndex]) - - - if len(self.selectedSubTask.QA_GUI_Task_List) == 0: - msg = QMessageBox() - msg.setIcon(QMessageBox.Information) - msg.setText("至少选中一个需要执行的任务!😹") - msg.setInformativeText("至少选中一个需要执行的任务") - msg.setWindowTitle("提示:") - msg.setDetailedText("操作提示: 请选勾选中需要执行的任务") - retval = msg.exec_() - return - - - #if self.qCheckBoxJob01_save_stock_day.isChecked(): - # self.job01_save_stock_day.start() - self.selectedSubTask.start() - - pass - - def doStopTask(self): - msg = QMessageBox() - msg.setIcon(QMessageBox.Information) - msg.setText("耐心是一种美德, 耐心等等结束哈!😹 ") - msg.setInformativeText("耐心是一种美德, 耐心等等结束哈😹 ") - msg.setWindowTitle("提示:") - msg.setDetailedText("操作提示: 其实是懒,不高兴去停止线程,怕有副作用,把数据库给搞坏了") - retval = msg.exec_() - - - def uiAllTaskStart(self, logInfo): - self.bntExecute.setEnabled(False) - pass - - def uiAllTaskDone(self, logInfo): - self.bntExecute.setEnabled(True) - pass \ No newline at end of file diff --git a/QUANTAXIS_Monitor_GUI/MainTabWindows/Tab02_WebpageCrawly_Old_no_use.py b/QUANTAXIS_Monitor_GUI/MainTabWindows/Tab02_WebpageCrawly_Old_no_use.py deleted file mode 100644 index 0581f6370..000000000 --- a/QUANTAXIS_Monitor_GUI/MainTabWindows/Tab02_WebpageCrawly_Old_no_use.py +++ /dev/null @@ -1,540 +0,0 @@ -import sys -import os -import threading -import subprocess -import time -import socket - -from PyQt5.QtCore import * -from PyQt5.QtGui import * -from PyQt5.QtWidgets import * -from PyQt5 import QtCore, QtGui, QtWidgets - -from datetime import datetime - - - -from QUANTAXIS.QAFetch.QAQuery import QA_fetch_stock_list -''' - spaghetti code 🍝, really need to more modulize - - main approach is: - launch the sepearte process to fire the chromedirver to fetch the eastmoney zjlx - use the socket communicate with the main GUI process - - 抓取东方财富的资金流向 - - 日期 收盘价 涨跌幅 主力净流入 超大单净流入 大单净流入 中单净流入 小单净流入 - 净额 净占比 净额 净占比 净额 净占比 净额 净占比 净额 净占比 -''' - -processNum = 8 -port_number_start = 4800 - - -mutex = threading.Lock() - - -# QRunnable 太高级, -# #emit the current sub process progress and log info the UI -#class Worker(QRunnable): -class Worker(QThread): - ''' - - ''' - def fetchCodeZjlx(self, fetchCode, process_port_int): - # Create a TCP/IP socket - sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - - # Connect the socket to the port where the server is listening - server_address = ('localhost', process_port_int) - #print('connecting to {} port {}'.format(*server_address)) - sock.connect(server_address) - - try: - - # Send data - # message = b'This is the message. It will be repeated.' - strMsg = 'read:%s' % fetchCode - message = strMsg.encode() - sock.sendall(message) - #print('sending {!r}'.format(message)) - - while True: - data = sock.recv(512) - if len(data) == 0: - time.sleep(1) - continue - - # print('received {!r}'.format(data)) - - cmdString = data.decode(); - cmdArry = cmdString.split('@') - - #print(cmdArry[0]) - cmd = cmdArry[0].strip('0') - #print(cmd) - - if (cmd == 'progress'): - #print('progress') - #print(cmdArry[1]) - strFloat = cmdArry[1] - iProgress = int(float(strFloat)*100) - self.trigger_new_sub_process_progress.emit(iProgress) - continue - - if (cmd == 'logging'): - #print('logging') - #print(cmdArry[1]) - strLogStr = cmdArry[1] - #self..emit(strLogStr) - self.trigger_new_sub_process_log.emit(strLogStr) - continue - - # if (cmd == 'data'): - # #print("收到 data is ") - # #print(cmdArry[1].encode('utf-8')) - # pass - - if (cmd == 'finished'): - #print('finish') - #print(cmdArry[1].encode('utf-8')) - strLogStr = cmdArry[1] - self.trigger_new_sub_process_log.emit(strLogStr) - - break; - except Exception as ee: - print(ee) - pass - - finally: - #print('closing socket') - sock.close() - - ''' - Worker thread - ''' - process_port = 0 - - #emit the current sub process progress and log info the UI - trigger_new_sub_process_log = pyqtSignal(str) - trigger_new_sub_process_progress = pyqtSignal(int) - - def handleNewSubProcessLog(self, vLog): - - self.progressLabel.setText(vLog) - - #filter the log message - if '股票资金流向' in vLog: - return - - rowCount = self.logTbl.rowCount() - newItem1 = QTableWidgetItem(vLog) - # newItem2 = QTableWidgetItem("QA_SU_save_stock_transaction") - self.logTbl.setRowCount(rowCount + 1) - self.logTbl.setItem(rowCount, 0, newItem1) - # self.logDisplay.setItem(rowCount, 1, newItem2) - - pass - - def handleNewSubProcessProgress(self, iProgress): - self.progressBar.setValue(iProgress) - pass - - #set the progress and label for the test - progressBar = None - progressLabel = None - totalProgressBar = None - totalProgressLabel = None - logTbl = None - - #@pyqtSlot() - def run(self): - ''' - Your code goes in this function - ''' - try: - - stockList = QA_fetch_stock_list() - stockCount =len(stockList) - - subStockList = [] - - - quotient = stockCount // processNum - remainder = stockCount % processNum - thread_num = self.process_port - port_number_start - - formStock = 0 - toStock = 0 - - if thread_num < processNum-1: - fromStock = thread_num * quotient + 0 - toStock = thread_num * quotient + quotient-1 - for i in range(quotient): - aStock = stockList[thread_num * quotient+i] - subStockList.append(aStock) - else: - if remainder != 0: - fromStock = thread_num * quotient + 0 - toStock = thread_num * quotient + remainder - 1 - for i in range(remainder): - aStock = stockList[thread_num * quotient + i] - subStockList.append(aStock) - else: - fromStock = thread_num * quotient + 0 - toStock = thread_num * quotient + quotient - 1 - for i in range(quotient): - aStock = stockList[thread_num * quotient + i] - subStockList.append(aStock) - - - subStockList.reverse() - - for i in range(50): - if i < len(subStockList[i]): - subStockList.remove(subStockList[i]) - - - print("thread_Port%d,一共获取股票%d个, 当前线程分配 %d, from %d to %d"%(self.process_port, stockCount, len(subStockList), fromStock, toStock)) - - except Exception as ee: - print(ee) - return - - for aStock in subStockList: - try: - fetchCode = aStock['code'] - #print("准备获取代码{}".format(fetchCode)) - self.fetchCodeZjlx(fetchCode, self.process_port) - #print("完成获取代码{}".format(fetchCode)) - - if mutex.acquire(): - #更新总体进度,这个是多线程 ,1/100 , 还剩1 , 1% - #labelAll = "%d/%d,还剩:%d,进度:%f" % (0, stockCountAll, stockCountAll, 0.0) - - txt = self.totalProgressLabel.text(); - - progres_lables = txt.split(',') - progress_stock_number = progres_lables[0].split('/') - - already_got = int(progress_stock_number[0]) - total_remain = int(progress_stock_number[1]) - already_got = already_got + 1 - - reamin_stock = total_remain - already_got - progress_percent = already_got / total_remain - - sRemainHour = progres_lables[3].split(':')[1] - labelAll = "%d/%d,还剩:%d,进度:%f,剩余小时:%s" % (already_got, total_remain, reamin_stock, progress_percent, sRemainHour) - self.totalProgressLabel.setText(labelAll) - mutex.release() - - except Exception as ee: - mutex.release() - print(ee) - pass - return - - - - -class TabWebpageCrawly(QWidget): - def __init__(self, parent=None): - super(TabWebpageCrawly, self).__init__(parent) - - - ''' - ------------ 总体进度条 - -------- 每个进程的进度 - -------- 每个进程的进度 日志 - -------- 每个进程的进度 - -------- 每个进程的进度 - - 启动所有进程 关闭所有进程 - ''' - def initUI(self): - ''' - - :return: - ''' - - self.hbox = QHBoxLayout(self) - - self.vboxR = QVBoxLayout(self) - self.vboxL = QVBoxLayout(self) - - self.labelAllProgress = QLabel(self) - self.labelAllProgress.setText("总体进度") - self.progressBarAll = QProgressBar(self) - - self.vboxL.addWidget(self.labelAllProgress) - self.vboxL.addWidget(self.progressBarAll) - - - self.subProgressBar = [] - self.subProcessLabel = [] - for i in range(processNum): - aBar = QProgressBar(self) - aLabel = QLabel(self) - - aLabel.setText("子进程%d:"%i) - self.subProgressBar.append(aBar) - self.subProcessLabel.append(aLabel) - - self.vboxL.addWidget(aLabel) - self.vboxL.addWidget(aBar) - - self.CmdLayout = QHBoxLayout(self) - - self.bntStart = QPushButton(self) - self.CmdLayout.addWidget(self.bntStart) - self.bntStart.setText("开始抓取") - - self.bntStop = QPushButton(self) - self.CmdLayout.addWidget(self.bntStop) - self.bntStop.setText("停止抓取") - - self.vboxL.addLayout(self.CmdLayout) - - self.logTbl = QTableWidget(self) - self.vboxR.addWidget(self.logTbl) - - self.hbox.addLayout(self.vboxL) - self.hbox.addLayout(self.vboxR) - - self.setLayout(self.hbox) - - self.bntStop.clicked.connect(self.doStop) - self.bntStart.clicked.connect(self.doStart) - #self.threadpool = QThreadPool() - - self.Thread_List = [] - # print("") - - self.logTbl.setColumnCount(5); - self.logTbl.setHorizontalHeaderLabels(['股票代码','记录数','开始日期','结束日期','是否需要更新']) - self.logTbl.setColumnWidth(0, 28) - self.logTbl.setColumnWidth(1, 28) - self.logTbl.setColumnWidth(2, 28) - self.logTbl.setColumnWidth(3, 28) - self.logTbl.setColumnWidth(4, 28) - - - self.timer = QTimer(self) # 初始化一个定时器 - self.timer.timeout.connect(self.updateTotalProgress) # 计时结束调用operate()方法 - - - pass - - # def xrange(x): - # return iter(range(x)) - - - def updateTotalProgress(self): - - try: - #if mutex.acquire(): - self.startup_task_time - current_task_time = datetime.now() - - # 任务运行的多长时间了 - already_elapse_second = (current_task_time - self.startup_task_time).seconds - - - txt = self.labelAllProgress.text(); - progres_lables = txt.split(',') - progress_stock_number = progres_lables[0].split('/') - - already_got = int(progress_stock_number[0]) - total_remain = int(progress_stock_number[1]) - - reamin_stock = total_remain - already_got - progress_percent = already_got / total_remain - sRemainHour = progres_lables[3].split(':')[1] - - - #计算 获取股票 需要的平均 秒数 - - if already_got > 0: - average_seconds_need_for_one_stock = already_elapse_second / already_got - - average_seconds_need_for_remain_stock = average_seconds_need_for_one_stock * reamin_stock - average_hours_need_for_remain_stock = average_seconds_need_for_remain_stock / 60.0 / 60.0 - - labelAll = "%d/%d,还剩:%d,进度:%f,剩余小时:%f" % \ - (already_got, total_remain, reamin_stock, progress_percent, average_hours_need_for_remain_stock) - self.labelAllProgress.setText(labelAll) - - #mutex.release() - - self.progressBarAll.setValue(int(progress_percent*10000)) - except Exception as ee: - print(ee) - pass - - - def doStart(self): - - self.bntStop.setEnabled(False) - self.bntStart.setEnabled(False) - - # 🛠todo 关闭上一次启动的服务区进程 - for i in range(processNum): - try: - process_port = str(port_number_start + i) - sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - - # Connect the socket to the port where the server is listening - server_address = ('localhost', int(process_port)) - # print('connecting to {} port {}'.format(*server_address)) - - sock.connect(server_address) - - strMsg = 'shutdown:shutdown' - message = strMsg.encode() - sock.sendall(message) - # print('sending {!r}'.format(message)) - - # print('closing socket') - #sock.close() - except Exception as ee: - # print(ee) - pass - - finally: - pass - - - # 检查数据库是否已经开启 - try: - stockListAll = QA_fetch_stock_list() - except Exception as ee: - #print(ee) - strError = ee.__str__() - msg = QMessageBox() - msg.setIcon(QMessageBox.Information) - msg.setText("获取股票代码失败,无法连接数据库!😹") - msg.setInformativeText(strError) - msg.setWindowTitle("提示:") - msg.setDetailedText(": 请确认mongodb 是否运行正常") - #retval = msg.exec_() - msg.exec() - return - - stockCountAll = len(stockListAll) - - labelAll = "%d/%d,还剩:%d,进度:%f,剩余小时:%s"%(0,stockCountAll,stockCountAll,0.0,'未知') - self.labelAllProgress.setText(labelAll) - - # 🛠todo - #print("启动服务进程") - - # xxxx/QUANTAXIS/QUANTAXIS_Monitor_GUI/MainTables/__file__ - realPath = os.path.realpath(__file__) # xxxx/QUANTAXIS/QUANTAXIS_Monitor_GUI/MainTables/__file__ - realDir0 = os.path.dirname(realPath); # xxxx/QUANTAXIS/QUANTAXIS_Monitor_GUI/MainTables - realDir1 = os.path.dirname(realDir0); # xxxx/QUANTAXIS/QUANTAXIS_Monitor_GUI - realDir2 = os.path.dirname(realDir1); - - for i in range(processNum): - process_port = str(port_number_start + i) - p = subprocess.Popen( - ['python', './QUANTAXIS_Monitor_GUI/TasksByProcess/SubSeleniumProcess.py', process_port], - cwd=realDir2) - #stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) - #print(p) - time.sleep(1) - # 尝试连接是否正常工作 - - # 🛠todo 判断服务进程socket是否已经就绪 - time.sleep(30) - - for i in range(processNum): - try: - #print("连接服务进程的线程") - worker = Worker() - - worker.logTbl = self.logTbl - - worker.totalProgressBar = self.progressBarAll - worker.totalProgressLabel = self.labelAllProgress - - worker.process_port = port_number_start + i - worker.progressBar = self.subProgressBar[i] - worker.progressLabel = self.subProcessLabel[i] - - worker.progressBar.setMaximum(10000) - worker.progressLabel.setText("准备开始。。。") - - # Worker cannot be converted to PyQt5.QtCore.QObject in this context - worker.trigger_new_sub_process_log.connect( worker.handleNewSubProcessLog) - worker.trigger_new_sub_process_progress.connect( worker.handleNewSubProcessProgress) - - - - #self.threadpool.start(self.worker) - #todo fix here 没有用到赞的 - self.Thread_List.append(worker) - - worker.start() - - time.sleep(1) - - except Exception as ee: - #print(ee) - pass - - self.startup_task_time = datetime.now() - self.timer.start(15000) # 设置计时间隔并启动, 更新整体进度 - - self.progressBarAll.setMaximum(1000000) - - self.bntStop.setEnabled(True) - #todo fixhere 完成所有的任务恢复这个按钮 - #self.bntStart.setEnabled(True) - - def doStop(self): - # self.threadpool. - self.bntStop.setEnabled(False) - - # 🛠todo 关闭chrome driver - for i in range(processNum): - try: - process_port = str(port_number_start + i) - sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - - # Connect the socket to the port where the server is listening - server_address = ('localhost', int(process_port)) - #print('connecting to {} port {}'.format(*server_address)) - - sock.connect(server_address) - - strMsg = 'shutdown:shutdown' - message = strMsg.encode() - sock.sendall(message) - #print('sending {!r}'.format(message)) - #print('closing socket') - #sock.close() - except Exception as ee: - #print(ee) - pass - - finally: - pass - - # 🛠todo mac 下面无效, - os.system("kill -9 $(ps -ef | grep chromedriver | awk '$0 !~/grep/ {print $2}' | tr -s '\n' ' ')") - - time.sleep(10) - # - - for iThread in self.Thread_List: - iThread.terminate() - - self.Thread_List.clear() - - self.bntStop.setEnabled(True) - self.bntStart.setEnabled(True) - - pass - diff --git a/QUANTAXIS_Monitor_GUI/MainTabWindows/Tab02_WebpageEastMoneyZJLX.py b/QUANTAXIS_Monitor_GUI/MainTabWindows/Tab02_WebpageEastMoneyZJLX.py deleted file mode 100644 index be6c24d35..000000000 --- a/QUANTAXIS_Monitor_GUI/MainTabWindows/Tab02_WebpageEastMoneyZJLX.py +++ /dev/null @@ -1,707 +0,0 @@ -import ast - - -from PyQt5.Qt import QDialog -from PyQt5.Qt import QMessageBox - -from PyQt5.QtGui import QCloseEvent -from PyQt5.QtCore import * -from PyQt5.QtGui import * -from PyQt5.QtWidgets import * -from PyQt5 import QtCore, QtGui, QtWidgets - - -from QUANTAXIS_Monitor_GUI.MainTabWindows.Tab0_RootClass import * -from QUANTAXIS_Monitor_GUI.AppMediator import * - - -#https://blog.csdn.net/henni_719/article/details/71706678 -from functools import partial - -''' - ------------ 总体进度条消息 - --------| 代码段:[600001~600188], 进度:111/188, 正在获取:600001 |地址|端口|启动连接进程|关闭进程操作| - 日志 - 600000, 打开网页失败 - 600111, 解析网页失败 - 600111, 打开网页成功 - 600111, 解析网页成功 - 600111, 插入数据库记录100条 日期从到结束 - ... - 分配股票 (开始,关闭所有进程) -''' - -processNumber = 9 -portNumberStart = 4500 - -class TabEastMoneyZJLX(TabRootClass): - - #进程开启关闭操作的日志到UI - #https://stackoverflow.com/questions/2970312/pyqt4-qtcore-pyqtsignal-object-has-no-attribute-connect - #https://www.cnblogs.com/tkinter/p/5632266.html - ''' - ??????如何程序化动态分配 静态 成员变量 ?????? - ''' - #todo fixhere - #use 动态的方法创建 静态变量 - # _array_trigger_sub_process_operation_log = [ - # pyqtSignal(str), pyqtSignal(str), pyqtSignal(str), pyqtSignal(str), - # pyqtSignal(str), pyqtSignal(str), pyqtSignal(str), pyqtSignal(str), - # pyqtSignal(str), pyqtSignal(str), pyqtSignal(str), pyqtSignal(str), - # ] - #############################################################################################################\ - # - # 😖😖 只能用这种方式 写 ? 不能动态创建 静态的 类变量 。。。。 - trigger_sub_process_operation_log_0 = pyqtSignal(str) - trigger_sub_process_operation_log_1 = pyqtSignal(str) - trigger_sub_process_operation_log_2 = pyqtSignal(str) - trigger_sub_process_operation_log_3 = pyqtSignal(str) - trigger_sub_process_operation_log_4 = pyqtSignal(str) - trigger_sub_process_operation_log_5 = pyqtSignal(str) - trigger_sub_process_operation_log_6 = pyqtSignal(str) - trigger_sub_process_operation_log_7 = pyqtSignal(str) - trigger_sub_process_operation_log_8 = pyqtSignal(str) - - # 😖😖 没办法, pyqtSignal 要求是 静态类变量,从 QObject继承 - def trigger_sub_process_operation_log_by_index(self, iIndex): - if iIndex == 0: - return self.trigger_sub_process_operation_log_0 - elif iIndex == 1: - return self.trigger_sub_process_operation_log_1 - elif iIndex == 2: - return self.trigger_sub_process_operation_log_2 - elif iIndex == 3: - return self.trigger_sub_process_operation_log_3 - elif iIndex == 4: - return self.trigger_sub_process_operation_log_4 - elif iIndex == 5: - return self.trigger_sub_process_operation_log_5 - elif iIndex == 6: - return self.trigger_sub_process_operation_log_6 - elif iIndex == 7: - return self.trigger_sub_process_operation_log_7 - elif iIndex == 8: - return self.trigger_sub_process_operation_log_8 - - ############################################################################################################# - - trigger_sub_process_label_0 = pyqtSignal(str) - trigger_sub_process_label_1 = pyqtSignal(str) - trigger_sub_process_label_2 = pyqtSignal(str) - trigger_sub_process_label_3 = pyqtSignal(str) - trigger_sub_process_label_4 = pyqtSignal(str) - trigger_sub_process_label_5 = pyqtSignal(str) - trigger_sub_process_label_6 = pyqtSignal(str) - trigger_sub_process_label_7 = pyqtSignal(str) - trigger_sub_process_label_8 = pyqtSignal(str) - - def trigger_sub_process_label_by_index(self, iIndex): - if iIndex == 0: - return self.trigger_sub_process_label_0 - elif iIndex == 1: - return self.trigger_sub_process_label_1 - elif iIndex == 2: - return self.trigger_sub_process_label_2 - elif iIndex == 3: - return self.trigger_sub_process_label_3 - elif iIndex == 4: - return self.trigger_sub_process_label_4 - elif iIndex == 5: - return self.trigger_sub_process_label_5 - elif iIndex == 6: - return self.trigger_sub_process_label_6 - elif iIndex == 7: - return self.trigger_sub_process_label_7 - elif iIndex == 8: - return self.trigger_sub_process_label_8 - - ############################################################################################################# - trigger_table_log_zjlx_db_status = pyqtSignal(str, str, str, int, str) - - # processId , code, op, ErrorMsg - trigger_table_process_thread_op_log = pyqtSignal(str,str,str,str) - trigger_table_error_log = pyqtSignal(str,str,str,str) - - def __init__(self, parent=None): - super(TabEastMoneyZJLX, self).__init__(parent) - - self.startTimer(500,Qt.CoarseTimer) - - def initUI(self): - - self.totalProgressBar = QProgressBar(self) - self.totalProgressLabel = QLabel(self) - self.totalProgressLabel.setMaximumHeight(28) - self.totalProgressBar.setMaximumHeight(28) - strTxt = "总体进度 :🐢 共个{} 股票🐍 {}/{}进度🦎".format(0,0,0) - self.totalProgressLabel.setText(strTxt) - - self.lstSubThreadBar = [] - self.lstSubThreadOpLabel = [] - - self.lstSubProcessOpMsg = [] - self.lstBntStartSubProcessSocketServer = [] - self.lstBntStopSubProcessSocketServer = [] - - self.lstTextEditAddress = [] - self.lstTextEditPort = [] - - self.lstBntStartJob = [] - self.lstBntStopJob = [] - - for iIndex in range(processNumber): - subProgressBar = QProgressBar(self) - strObjName = "subProcessBar_%d" % iIndex - subProgressBar.setObjectName(strObjName) - self.lstSubThreadBar.append(subProgressBar) - - subProgressLabel = QLabel(self) - strObjName = "subProcessLabel_%d" % iIndex - subProgressLabel.setObjectName(strObjName) - self.lstSubThreadOpLabel.append(subProgressLabel) - - ''' - https://blog.csdn.net/fengyu09/article/details/39498777 - ''' - - bntStartSubProcessSocketServer = QPushButton(self) - bntStartSubProcessSocketServer.setText("⚙️启动进程") - strObjName = "startProcessBnt_%d" % iIndex - bntStartSubProcessSocketServer.setObjectName(strObjName) - bntStartSubProcessSocketServerClick = partial(self.doStartSubProcess,strObjName) - bntStartSubProcessSocketServer.clicked.connect(bntStartSubProcessSocketServerClick) - bntStartSubProcessSocketServer.setEnabled(True) - self.lstBntStartSubProcessSocketServer.append(bntStartSubProcessSocketServer) - - - bntStopSubProcessSocketServer = QPushButton(self) - bntStopSubProcessSocketServer.setText("⭕️停止进程") - strObjName = "stopProcessBnt_%d" % iIndex - bntStopSubProcessSocketServer.setObjectName(strObjName) - bntStopSubProcessSocketServerClick = partial(self.doStopSubProcess,strObjName) - bntStopSubProcessSocketServer.clicked.connect(bntStopSubProcessSocketServerClick) - bntStopSubProcessSocketServer.setEnabled(True) - self.lstBntStopSubProcessSocketServer.append(bntStopSubProcessSocketServer) - - #todo check ip address - #rx = QRegExp("\\b(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\b"); - - txtEditAddress = QLineEdit(self) - txtEditAddress.setPlaceholderText("localhost") - txtEditAddress.setMinimumWidth(105) - txtEditAddress.setMaximumWidth(90) - strObjName = "txtAddressLineEdit_%d" % iIndex - txtEditAddress.setObjectName(strObjName) - self.lstTextEditAddress.append(txtEditAddress) - - txtEditPort = QLineEdit(self) - txtEditPort.setPlaceholderText(str(portNumberStart + iIndex)) - txtEditPort.setMaximumWidth(50) - txtEditPort.setMinimumWidth(40) - strObjName= "txtPortLineEdit_%d"%iIndex - txtEditPort.setObjectName(strObjName) - self.lstTextEditPort.append(txtEditPort) - - - subProcessStartJob = QPushButton(self) - subProcessStartJob.setText("🚩开始获取") - subProcessStartJob.setMaximumWidth(100) - strObjName= "startJobBnt_%d"%iIndex - subProcessStartJob.setObjectName(strObjName) - subProcessStartJobClick = partial(self.cmdProcessDoJobByThread, strObjName) - subProcessStartJob.clicked.connect(subProcessStartJobClick) - self.lstBntStartJob.append(subProcessStartJob) - - subProcessStopJob = QPushButton(self) - subProcessStopJob.setText("🛑停止获取") - subProcessStopJob.setMaximumWidth(100) - strObjName= "stopJobBnt_%d"%iIndex - subProcessStopJob.setObjectName(strObjName) - subProcessStopJobClick = partial(self.cmdProcessStopJobByThread, strObjName) - subProcessStopJob.clicked.connect(subProcessStopJobClick) - self.lstBntStopJob.append(subProcessStopJob) - - subProcessLogDetailMsg = QLabel(self) - subProcessLogDetailMsg.setText('.......没有启动.......') - strObjName= "logDetailLabel_%d"%iIndex - subProcessLogDetailMsg.setObjectName(strObjName) - self.lstSubProcessOpMsg.append(subProcessLogDetailMsg) - - # 进程操作状态 - try: - strObjName = "logProcessOperationLog_%d" % iIndex - sub_process_op_log_partial_fun = partial(self.doSubProcessOpLog, strObjName) - self.trigger_sub_process_operation_log_by_index(iIndex).connect(sub_process_op_log_partial_fun) - - except Exception as ee: - strErrorMsg = ee.__str__() - print(strErrorMsg) - pass - - #进程 的工作进度 - try: - strObjName = "logProcessProgressLog_%d" % iIndex - sub_process_label_partial_fun = partial(self.doSubProcessProgressLabelUpdate, strObjName) - self.trigger_sub_process_label_by_index(iIndex).connect(sub_process_label_partial_fun) - - except Exception as ee: - strErrorMsg = ee.__str__() - print(strErrorMsg) - pass - - self.trigger_table_log_zjlx_db_status.connect(self.acceptLogToUI) - self.trigger_table_process_thread_op_log.connect(self.acceptProcessThreadOpLogToTable) - self.trigger_table_error_log.connect(self.acceptErrorLogToTable) - - # it does not works - #for iIndex in range(processNumber): - #eval(self.lstBntStopSubProcessSocketServer[iIndex].clicked.connect(lambda: self.doStartSubProcess(iIndex))) - #print("-->", self.lstBntStopSubProcessSocketServer[iIndex]) - #self.lstBntStopSubProcessSocketServer[0].clicked.connect(lambda: self.doStopSubProcess(0)) - #self.lstBntStopSubProcessSocketServer[1].clicked.connect(lambda: self.doStopSubProcess(1)) - #self.lstBntStopSubProcessSocketServer[2].clicked.connect(lambda: self.doStopSubProcess(2)) - #self.lstBntStopSubProcessSocketServer[3].clicked.connect(lambda: self.doStopSubProcess(3)) - #self.lstBntStopSubProcessSocketServer[4].clicked.connect(lambda: self.doStopSubProcess(4)) - #self.lstBntStopSubProcessSocketServer[5].clicked.connect(lambda: self.doStopSubProcess(5)) - - - self.bntAssignStock = QPushButton(self) - self.bntAssignStock.setText('🗂分配股票到每个工作进程') - - self.bntStartAllProcsss = QPushButton(self) - self.bntStartAllProcsss.setText('▶️开始获取数据') - - - self.bntStopAllProcsss = QPushButton(self) - self.bntStopAllProcsss.setText('🔴停止获取') - - ###########################################################################3 - - self.bntAssignStock.clicked.connect(self.assignStockListSegment) - - self.bntStopAllProcsss.clicked.connect(self.stopAllThread) - self.bntStartAllProcsss.clicked.connect(self.startAllThread) - - ###########################################################################3 - self.dbRecordStatusLabel = QLabel(self) - self.dbRecordStatusLabel.setText('(东方财富网页版只提供最近100天的资金流向)') - self.tableRecordsStatusLog =QTableWidget(self) - self.subProcessProgressLabel = QLabel(self) - self.subProcessProgressLabel.setText('获取操作日志') - self.tableProcessThreadOpLog = QTableWidget(self) - - self.subProcessErrorLabel = QLabel(self) - self.subProcessErrorLabel.setText('错误操作日志') - self.tableErrorLog = QTableWidget(self) - - self.rootHLayout = QHBoxLayout(self) - - self.leftVLayout = QVBoxLayout(self) - self.rightVLayout = QVBoxLayout(self) - - self.topHLayout = QHBoxLayout(self) - - self.topHLayout.addWidget(self.totalProgressLabel) - self.topHLayout.addWidget(self.totalProgressBar) - - self.leftVLayout.setSpacing(1) - self.leftVLayout.addLayout(self.topHLayout) - - index = 0 - for index in range(processNumber): - - middleHLayout0 = QHBoxLayout(self) - middleHLayout0.addWidget(self.lstBntStartJob[index]) - middleHLayout0.addWidget(self.lstBntStopJob[index]) - middleHLayout0.addWidget(self.lstSubProcessOpMsg[index]) - - middleHLayout0.addWidget(self.lstBntStartSubProcessSocketServer[index]) - middleHLayout0.addWidget(self.lstBntStopSubProcessSocketServer[index]) - middleHLayout0.addWidget(self.lstTextEditAddress[index]) - middleHLayout0.addWidget(self.lstTextEditPort[index]) - - self.leftVLayout.addLayout(middleHLayout0) - - middleHLayout = QHBoxLayout(self) - middleHLayout.setSpacing(1) - - middleHLayout.addWidget(self.lstSubThreadOpLabel[index]) - middleHLayout.addWidget(self.lstSubThreadBar[index]) - - - self.leftVLayout.addLayout(middleHLayout) - - self.bottomBntsHLayout = QHBoxLayout() - self.bottomBntsHLayout.addWidget(self.bntAssignStock) - self.bottomBntsHLayout.addWidget(self.bntStartAllProcsss) - self.bottomBntsHLayout.addWidget(self.bntStopAllProcsss) - - self.leftVLayout.addLayout(self.bottomBntsHLayout) - - self.rightVLayout.addWidget(self.dbRecordStatusLabel) - self.rightVLayout.addWidget(self.tableRecordsStatusLog) - self.rightVLayout.addWidget(self.subProcessProgressLabel) - self.rightVLayout.addWidget(self.tableProcessThreadOpLog) - self.rightVLayout.addWidget(self.subProcessErrorLabel) - self.rightVLayout.addWidget(self.tableErrorLog) - - self.rootHLayout.addLayout(self.leftVLayout) - self.rootHLayout.addLayout(self.rightVLayout) - - self.setLayout(self.rootHLayout) - - - #初始化界面 - for iIndex in range(processNumber): - strLog = "❓💤进程%d还没有启动💤❓" % iIndex - self.trigger_sub_process_operation_log_by_index(iIndex).emit(strLog) - - for iIndex in range(processNumber): - strTxt = '🐌%d进程,没有分配代码段:[xxxxxxx,xxxxxx],进度:0/xxxx,操作日志'%iIndex - self.trigger_sub_process_label_by_index(iIndex).emit(strTxt) - - - for iIndex in range(processNumber): - self.lstSubThreadBar[iIndex].setMaximum(10000) - # self.dbRecordsStatusLog.setColumnCount(1) - # self.dbRecordsStatusLog.setHorizontalHeaderLabels(['股票代码']) - # self.dbRecordsStatusLog.setColumnWidth(0, 700) - - self.tableRecordsStatusLog.setAutoScroll(True) - self.tableRecordsStatusLog.setColumnCount(5); - self.tableRecordsStatusLog.setHorizontalHeaderLabels(['股票代码', '开始日期', '结束日期', '记录数', '是否更新']) - self.tableRecordsStatusLog.setColumnWidth(0, 65) - self.tableRecordsStatusLog.setColumnWidth(1, 85) - self.tableRecordsStatusLog.setColumnWidth(2, 85) - self.tableRecordsStatusLog.setColumnWidth(3, 65) - self.tableRecordsStatusLog.setColumnWidth(4, 55) - - - - self.tableProcessThreadOpLog.setColumnCount(4) - self.tableProcessThreadOpLog.setHorizontalHeaderLabels(['进程#', '代码', '操作', '日志内容']) - - self.tableProcessThreadOpLog.setColumnWidth(0, 18) - self.tableProcessThreadOpLog.setColumnWidth(1, 95) - self.tableProcessThreadOpLog.setColumnWidth(2, 95) - self.tableProcessThreadOpLog.setColumnWidth(3, 95) - - - - self.tableErrorLog.setHorizontalHeaderLabels(['进程#', '代码', '操作', '日志内容']) - self.tableErrorLog.setColumnCount(4) - - self.tableErrorLog.setColumnWidth(0, 18) - self.tableErrorLog.setColumnWidth(1, 95) - self.tableErrorLog.setColumnWidth(2, 95) - self.tableErrorLog.setColumnWidth(3, 95) - - - self.tableErrorLog.setMaximumWidth(65 + 85 + 85 + 65 + 55 + 50) - self.tableProcessThreadOpLog.setMaximumWidth(65 + 85 + 85 + 65 + 55 + 50) - self.tableRecordsStatusLog.setMaximumWidth(65 + 85 + 85 + 65 + 55 + 50) - - - ############################################################################################################# - - def doDummy(self): - pass - - def stopAllThread(self): - - msg = QMessageBox() - msg.setIcon(QMessageBox.Information) - msg.setText("🤑还未实现,请一个个点击 按钮关闭进程!😹 ") - msg.setInformativeText("🙄一次关闭,电脑会变得很慢,后期实现😹 ") - msg.setWindowTitle("操作提示:") - msg.setDetailedText("🤮笔记本电脑严重发烫") - retval = msg.exec() - pass - - def startAllThread(self): - - msg = QMessageBox() - msg.setIcon(QMessageBox.Information) - msg.setText("😯还未实现,请一个个点击 按钮启动进程!😹 ") - msg.setInformativeText("🤐一次启动,电脑会变得很慢,后期实现😹 ") - msg.setWindowTitle("😬操作提示:") - msg.setDetailedText("🤔笔记本电脑严重发烫") - retval = msg.exec() - pass - ############################################################################################################# - def acceptLogToUI(self, strCol0, strCol1, strCol2, intCol3, strCol4): - - # fieldArray = strToLog.split('_') - # if fieldArray[1] is not None: - # jsonRec = ast.literal_eval(fieldArray[1]) - # - # - # - rowCount = self.tableRecordsStatusLog.rowCount() - try: - self.tableRecordsStatusLog.setRowCount(rowCount + 1) - if strCol0 is not None: - col0 = QTableWidgetItem(strCol0) - self.tableRecordsStatusLog.setItem(rowCount, 0, col0) - - if strCol1 is not None: - col1 = QTableWidgetItem(strCol1) - self.tableRecordsStatusLog.setItem(rowCount, 1, col1) - - if strCol2 is not None: - col2 = QTableWidgetItem(strCol2) - self.tableRecordsStatusLog.setItem(rowCount, 2, col2) - - if intCol3 is not None: - col3 = QTableWidgetItem(str(intCol3)) - self.tableRecordsStatusLog.setItem(rowCount, 3, col3) - - if strCol4 is not None: - col4 = QTableWidgetItem(strCol4) - self.tableRecordsStatusLog.setItem(rowCount, 4, col4) - except Exception as ee: - print(ee) - ############################################################################################################# - - def acceptProcessThreadOpLogToTable(self, strProcessIndex, strProcessCode, strOperation, strMessage): - - try: - - iProcessIndex = int(strProcessIndex) - mediator = self.getMediator(); - - strOp0 = "✅解析网页中🕷进度日期报告" - if strOperation == strOp0: - - strTxt = self.lstSubThreadOpLabel[iProcessIndex].text(); - strArr = strTxt.split(',') - - #strTxtNew = '🐌%d进程,没有分配代码段:[xxxxxxx,xxxxxx],进度:0/xxxx,操作日志' % iProcessIndex - strArr[3] = strMessage - - newStr = strArr[0]+','+strArr[1]+','+strArr[2]+','+strArr[3] - self.lstSubThreadOpLabel[iProcessIndex].setText(newStr) - return - - strOp1 = "✅解析网页中🐞进度条报告" - if strOperation == strOp1: - iProgress = int(float(strMessage)*100) - self.lstSubThreadBar[iProcessIndex].setValue(iProgress) - - return - - strOp2 = "✅写入🐜数据库OK" - # 保存当前 的 check point 进度! - if strOperation == strOp2: - - #保存当前进度 - mediator.addSuccessCodeToCheckPoint(strProcessIndex) - - # # 更新进度 - # iProcessIndex = int(strProcessIndex) - strTxt = self.lstSubThreadOpLabel[iProcessIndex].text(); - strArr = strTxt.split(',') - strProgress = strArr[2].split(':') - # - strAllNumberProgress = strProgress[1].split('/') - strGotNumber = mediator.getSuccessCodeCheckPointCount(strProcessIndex) - # - newStr = strArr[0]+','+strArr[1]+','+strProgress[0]+':'+str(strGotNumber)+"/"+strAllNumberProgress[1]+","+strArr[3] - # - self.lstSubThreadOpLabel[iProcessIndex].setText(newStr) - - rowCount = self.tableProcessThreadOpLog.rowCount() - self.tableProcessThreadOpLog.setRowCount(rowCount + 1) - - if strProcessIndex is not None: - col0 = QTableWidgetItem(strProcessIndex) - self.tableProcessThreadOpLog.setItem(rowCount, 0, col0) - - if strProcessCode is not None: - col1 = QTableWidgetItem(strProcessCode) - self.tableProcessThreadOpLog.setItem(rowCount, 1, col1) - - if strOperation is not None: - col2 = QTableWidgetItem(strOperation) - self.tableProcessThreadOpLog.setItem(rowCount, 2, col2) - - if strMessage is not None: - col3 = QTableWidgetItem(str(strMessage)) - self.tableProcessThreadOpLog.setItem(rowCount, 3, col3) - - except Exception as ee: - print(ee) - - - - def acceptErrorLogToTable(self,strProcessIndex, strProcessCode, strOperation, strErrorMessage ): - - rowCount = self.tableErrorLog.rowCount() - try: - self.tableErrorLog.setRowCount(rowCount + 1) - - if strProcessIndex is not None: - col0 = QTableWidgetItem(strProcessIndex) - self.tableErrorLog.setItem(rowCount, 0, col0) - - if strProcessCode is not None: - col1 = QTableWidgetItem(strProcessCode) - self.tableErrorLog.setItem(rowCount, 1, col1) - - if strOperation is not None: - col2 = QTableWidgetItem(strOperation) - self.tableErrorLog.setItem(rowCount, 2, col2) - - if strErrorMessage is not None: - col3 = QTableWidgetItem(str(strErrorMessage)) - self.tableErrorLog.setItem(rowCount, 3, col3) - - except Exception as ee: - print(ee) - - - ############################################################################################################# - def doSubProcessProgressLabelUpdate(self,strObjName, strLabelString): - print('trigger_sub_process_progress_update {} emit {}'.format(strObjName, strLabelString)) - args0 = strObjName.split('_') - iIndex = int(args0[1]) - #self.lstSubProcessLogDetialMsg[iIndex].setText(strLogString) - self.lstSubThreadOpLabel[iIndex].setText(strLabelString) - - pass - - def doSubProcessOpLog(self, strObjName, strLogString): - print('trigger_sub_process_operation_log {} emit {}'.format(strObjName, strLogString)) - args0 = strObjName.split('_') - iIndex = int(args0[1]) - - self.lstSubProcessOpMsg[iIndex].setText(strLogString) - - pass - - ############################################################################################################# - def doStartSubProcess(self, strObjName): - print('Button {} clicked'.format(strObjName)) - - args0 = strObjName.split('_') - iIndex = int(args0[1]) - - strAddress = self.lstTextEditAddress[iIndex].text() - strPort = self.lstTextEditPort[iIndex].text() - - #todo fix here - if strAddress!="" and strAddress!='localhost': - msg = QMessageBox() - msg.setIcon(QMessageBox.Information) - msg.setText("尝试启动远程服务进程!😹 ") - msg.setInformativeText("不是本地localhost本地进程😹 ") - msg.setWindowTitle("操作提示:") - msg.setDetailedText("请在远程机器上启动本程序启动服务进程") - retval = msg.exec() - return - - if strAddress == "": - strAddress = 'localhost' - if strPort == "": - strPort = str(portNumberStart + iIndex) - - - mediator = self.getMediator() - bRetOk = mediator.startUpEastMoneyZjlxProcess(self, iIndex,strAddress,strPort) - - # if bRetOk: - # self.lstBntStartSubProcessSocketServer[iIndex].setEnabled(False) - # self.lstBntStopSubProcessSocketServer[iIndex].setEnabled(True) - # - # self.lstTextEditPort[iIndex].setEnabled(False) - # self.lstTextEditAddress[iIndex].setEnabled(False) - - def doStopSubProcess(self, strObjName): - print('Button {} clicked'.format(strObjName)) - args0 = strObjName.split('_') - iIndex = int(args0[1]) - strAddress = self.lstTextEditAddress[iIndex].text() - strPort = self.lstTextEditPort[iIndex].text() - - #todo fix here - if strAddress!="" and strAddress!='localhost': - msg = QMessageBox() - msg.setIcon(QMessageBox.Information) - msg.setText("远程程服务进程!😹 ") - msg.setInformativeText("不是本地localhost本地进程😹 ") - msg.setWindowTitle("操作提示:") - msg.setDetailedText("请在远程机器上关闭服务进程") - retval = msg.exec() - return - - if strAddress == "": - strAddress = 'localhost' - if strPort == "": - strPort = portNumberStart + iIndex - - mediator = self.getMediator() - - - - mediator.shutdownEastMoneyZjlxProcess(self, iIndex,strAddress,strPort) - - # self.lstBntStartSubProcessSocketServer[iIndex].setEnabled(True) - # self.lstBntStopSubProcessSocketServer[iIndex].setEnabled(False) - # - # self.lstTextEditPort[iIndex].setEnabled(True) - # self.lstTextEditAddress[iIndex].setEnabled(True) - pass - - ############################################################################################################# - def cmdProcessDoJobByThread(self, strObjName): - print('Button {} clicked'.format(strObjName)) - args0 = strObjName.split('_') - iIndex = int(args0[1]) - - mediator = self.getMediator() - - - strAddress = self.lstTextEditAddress[iIndex].text() - strPort = self.lstTextEditPort[iIndex].text() - - if strAddress == "": - strAddress = 'localhost' - if strPort == "": - strPort = str(portNumberStart + iIndex) - - mediator.cmdProcessDoTheJob(self,iIndex,strAddress, int(strPort) ) - - - def cmdProcessStopJobByThread(self, strObjName): - print('Button {} clicked'.format(strObjName)) - args0 = strObjName.split('_') - iIndex = int(args0[1]) - - mediator = self.getMediator() - - - strAddress = self.lstTextEditAddress[iIndex].text() - strPort = self.lstTextEditPort[iIndex].text() - - if strAddress == "": - strAddress = 'localhost' - if strPort == "": - strPort = str(portNumberStart + iIndex) - - mediator.cmdProcessStopTheJob(self, iIndex, strAddress, int(strPort)) - - - ############################################################################################################# - def assignStockListSegment(self): - # ask mediator to fetch the segment of stock code - mediator = self.getMediator() - mediator.assignStockListSegment(self) - pass - - - def timerEvent(self, a0: 'QTimerEvent'): - - mediator = self.getMediator() - mediator.updateCurrentProcessThreadStatus(self) - - pass \ No newline at end of file diff --git a/QUANTAXIS_Monitor_GUI/MainTabWindows/Tab03_DataCheck.py b/QUANTAXIS_Monitor_GUI/MainTabWindows/Tab03_DataCheck.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/QUANTAXIS_Monitor_GUI/MainTabWindows/Tab04_BlockStatistics.py b/QUANTAXIS_Monitor_GUI/MainTabWindows/Tab04_BlockStatistics.py deleted file mode 100644 index 7a85f4131..000000000 --- a/QUANTAXIS_Monitor_GUI/MainTabWindows/Tab04_BlockStatistics.py +++ /dev/null @@ -1,413 +0,0 @@ -#encoding:utf-8 - - -from PyQt5.QtCore import * -from PyQt5.QtGui import * -from PyQt5.QtWidgets import * - - - -from QUANTAXIS.QAFetch.QAQuery import QA_fetch_stock_block - - -from QUANTAXIS_Monitor_GUI.ProgressDlgs.ProgressDlg_WithThreading import * -from QUANTAXIS_Monitor_GUI.TasksByThreading.QThread_CheckStockBlock_DB_Task import * -''' ------------------------------------------------- -板块名称| 股票个数 | 上涨家数 | 下跌家数 | 资金流向 | ------------------------------------------------- -板块1 | 22 | 10 | 12 | | ------------------------------------------------- -板块2 | 22 | 10 | 12 | | ------------------------------------------------- -板块2 | 22 | 10 | 12 | | ------------------------------------------------- - -每个板块的股票列表基本信息 ------------------------------------------------- -股票名字| 收盘价 | 涨幅 | 成交额 | | ------------------------------------------------- - - - -更新板块统计数据 - -输出类似的统计信息 -2018-07-31 16.56.47: 沪深 上涨板块信息 -1: 石油化工 板块 总共24只股票,50.0% 股票上涨 - -提示:-----以下是板块涨幅小于40%,不建议选择---- - -2: 原油期货 板块 总共8只股票,37.0% 股票上涨 -3: 粤港澳自贸区 板块 总共11只股票,27.0% 股票上涨 -4: 农业产品 板块 总共19只股票,26.0% 股票上涨 -5: 传感器 板块 总共4只股票,25.0% 股票上涨 -6: 动漫 板块 总共4只股票,25.0% 股票上涨 -7: 包装食品 板块 总共21只股票,23.0% 股票上涨 -8: 白酒 板块 总共17只股票,23.0% 股票上涨 -9: 苹果供应链 板块 总共13只股票,23.0% 股票上涨 - - ------------------- 下跌板块信息 -------- -1: 纺织服装设备 板块 总共7只股票,42.0%(3只)股票下跌 -2: 分立器件 板块 总共6只股票,33.0%(2只)股票下跌 -3: 新股次新股 板块 总共20只股票,25.0%(5只)股票下跌 -4: 航母 板块 总共8只股票,25.0%(2只)股票下跌 -5: 高铁 板块 总共12只股票,25.0%(3只)股票下跌 -6: 智能家居 板块 总共27只股票,22.0%(6只)股票下跌 -7: 船舶制造 板块 总共9只股票,22.0%(2只)股票下跌 -8: 装饰工程 板块 总共9只股票,22.0%(2只)股票下跌 -9: 超市连锁 板块 总共9只股票,22.0%(2只)股票下跌 -''' - - -class MyTableModel(QAbstractTableModel): - def __init__(self,stock_block_list=None, parent=None, *args): - - QAbstractTableModel.__init__(self, parent, *args) - - # 🛠 todo 实现排序, - self.arraydata = [ - ['22', '44', '55', '22'], - ['050', '01', '02', '33'], - ['130', '11', '12', '43'], - ['220', '21', '22', '53'], - ['30', '21', '22', '63'], - ['290', '21', '22', '73'], - ['220', '21', '22', '93']] - - self.stock_block_list = stock_block_list - - - allRowNumberCount = 0 - data_row_from_df = None - - def rowCount(self, parent): - if self.stock_block_list is not None: - try: - block_size = len(self.stock_block_list) - except Exception as ee: - errMsg = ee.__str__() - print(errMsg) - - return block_size - else: - return 0 - - #列的个数 - - headerList = ['板块名字', '股票个数', '上涨家数', '下跌家数', '上涨比率','下跌比率'] - def columnCount(self, parent): - return len(self.headerList) - - - def data(self, index, role): - #print("return date => %d %d", index.row(), index.column()) - if not index.isValid(): - return QVariant() - elif role != Qt.DisplayRole: - return QVariant() - else: - #aData = self.arraydata[index.row()][index.column()] - - if self.stock_block_list is not None: - #data_row_from_df = self.block_list_df.iloc[[2]] - #print(data_row_from_df) - - if index.column() == 0: - dictKey = list(self.stock_block_list)[index.row()] - aQVariant = QVariant(dictKey) - - elif index.column() == 1: - dictKey = list(self.stock_block_list)[index.row()] - stockCount = self.stock_block_list[dictKey]['count'] - aQVariant = QVariant(stockCount) - - elif index.column() == 2: - dictKey = list(self.stock_block_list)[index.row()] - stockCount = self.stock_block_list[dictKey]['up'] - aQVariant = QVariant(stockCount) - - elif index.column() == 3: - dictKey = list(self.stock_block_list)[index.row()] - stockCount = self.stock_block_list[dictKey]['down'] - aQVariant = QVariant(stockCount) - else: - aQVariant = QVariant("") - else: - strMsg = "{},{}".format(index.row(), index.column()) - aQVariant = QVariant(strMsg) - return aQVariant - - - # 🛠 todo 实现排序, - def sort(self, Ncol, order): - """Sort table by given column number. - """ - #self.emit(SIGNAL("layoutAboutToBeChanged()")) - #self.arraydata = sorted(self.arraydata, key=operator.itemgetter(Ncol)) - #if order == Qt.DescendingOrder: - # self.arraydata.reverse() - #self.emit(SIGNAL("layoutChanged()")) - - try: - if order == Qt.DescendingOrder: - - for rowIndex in range(len(self.arraydata)): - #maxRowLine = self.arraydata[rowIndex] - for compareRowIndex in range( len(self.arraydata), rowIndex , -1): - if self.arraydata[rowIndex][Ncol] > self.arraydata[compareRowIndex-1][Ncol]: - #swap maxRowIndex compareRowIndex - tmepRow = self.arraydata[rowIndex] - self.arraydata[rowIndex] = self.arraydata[compareRowIndex-1] - self.arraydata[compareRowIndex-1] = tmepRow - - elif order == Qt.AscendingOrder: - - for rowIndex in range(len(self.arraydata)): - #maxRowLine = self.arraydata[rowIndex] - for compareRowIndex in range( len(self.arraydata), rowIndex , -1): - if self.arraydata[rowIndex][Ncol] < self.arraydata[compareRowIndex-1][Ncol]: - #swap maxRowIndex compareRowIndex - tmepRow = self.arraydata[rowIndex] - self.arraydata[rowIndex] = self.arraydata[compareRowIndex-1] - self.arraydata[compareRowIndex-1] = tmepRow - - self.layoutChanged.emit() - - except Exception as ee: - strError = ee.__str__() - print(strError) - pass - - #print("") - #passself.layoutChanged() - #self.layoutChanged() - - - - def headerData(self, col, orientation, role): # real signature unknown; restored from __doc__ - """ headerData(self, int, Qt.Orientation, role: int = Qt.DisplayRole) -> Any """ - - # else: - # return QVariant("0") - # #if Qt_Orientation == 1: - # # if p_int == 0: - # # return QVariant(self.headerList[0]) - # # if p_int == 1: - # # return QVariant(self.headerList[0]) - # # if p_int == 2: - # # return QVariant(self.headerList[0]) - # # if p_int == 3: - # # return QVariant(self.headerList[0]) - # return QVariant(self.headerList[p_int]) - - if orientation == Qt.Horizontal and role == Qt.DisplayRole: - return QVariant(self.headerList[col]) - return QVariant() - - # if role== Qt.DisplayRole: - # if orientation == Qt.Horizontal: - # return QVariant(self.headerList[col]) - # else: - # return QVariant(col) - #pass - - - def setDataList(self): - self.allRowNumberCount = self.allRowNumberCount + 1 - - - #self.layoutAboutToBeChanged.emit() - #self.dataChanged.emit(self.createIndex(0, 0), self.createIndex(self.rowCount(0), self.columnCount(0))) - #self.layoutChanged.emit() - pass - -class TabBlockStatistics(QWidget): - def __init__(self, parent=None): - super(TabBlockStatistics, self).__init__(parent) - - - - def initUI(self): - - try: - - ####################################################################################### - self.tableViewBlock = QTableView(self) - - self.modelBlock = MyTableModel(self,stock_block_list=None) - - #titleBlockNames = ['板块名字', '股票个数', '上涨家数', '下跌家数', '上涨比率','下跌比率'] - - #self.modelBlock.setHorizontalHeaderLabels(titleBlockNames) - - self.tableViewBlock.setModel(self.modelBlock) - - # set the minimum size - self.tableViewBlock.setMinimumSize(400, 300) - - # hide grid - self.tableViewBlock.setShowGrid(True) - - # set the font - font = QFont("Courier New", 13) - self.tableViewBlock.setFont(font) - - # hide vertical header - vh = self.tableViewBlock.verticalHeader() - vh.setVisible(False) - - # set horizontal header properties - hh = self.tableViewBlock.horizontalHeader() - hh.setStretchLastSection(True) - - # set column width to fit contents - #self.tableViewBlock.resizeColumnsToContents() - - # set row height - # nrows = len(self.tabledata) - # for row in xrange(nrows): - # tv.setRowHeight(row, 18) - - # enable sorting - #self.tableViewBlock.setSortingEnabled(True) - - self.tableViewBlock.setSortingEnabled(True) - - - #self.modelBlock = QStockBlockListModel() - - # item = QStandardItem(str("1data")) - # self.modelBlock.setItem(1, 0, item) - # - # item = QStandardItem(str("z3ata")) - # self.modelBlock.setItem(2, 0, item) - # - # item = QStandardItem(str("f4data")) - # self.modelBlock.setItem(3, 0, item) - # # self.modelBlock.setItem(0, 1, item) - # self.modelBlock.setItem(0, 2, item) - # self.modelBlock.setItem(0, 3, item) - # - # self.tableViewBlock.setModel(self.modelBlock) - # - # self.tableViewBlock.sortByColumn(0,Qt.AscendingOrder) - - ####################################################################################### - # self.tableViewSubBockStocks = QTableView(self) - # - # self.modelSubBlockStock = QStandardItemModel() - # titleSubBlockNames = ['股票代码', '收盘价', '上涨', '成交额', '成交量'] - # self.modelSubBlockStock.setHorizontalHeaderLabels(titleSubBlockNames) - # - # self.tableViewSubBockStocks.setModel(self.modelSubBlockStock) - ##################################################################################### - pass - except Exception as ee: - print(ee) - - self.txtArea = QTextEdit(self) - self.txtArea.setMaximumWidth(300) - - - self.bntLoadData = QPushButton() - self.bntLoadData.setText('加载数据 🥑🍋🥝') - - self.bntLoadData.clicked.connect(self.LoadDataClick) - - self.bntStatistic = QPushButton() - self.bntStatistic.setText('统计板块涨跌 📊🗂💹') - - - self.bntStatistic.clicked.connect(self.doStatistic) - - ####################################################################################### - # layout: - self.myRootLayout = QHBoxLayout(self) - - self.myLeftLayout = QVBoxLayout(self) - self.myRightLayout = QVBoxLayout(self) - - self.myLeftBottomButtonsHLayout = QHBoxLayout(self) - self.myLeftBottomButtonsHLayout.addWidget(self.bntLoadData) - self.myLeftBottomButtonsHLayout.addWidget(self.bntStatistic) - - self.myRootLayout.addLayout(self.myLeftLayout) - self.myRootLayout.addLayout(self.myRightLayout) - - self.myLeftLayout.addWidget(self.tableViewBlock) - #self.myLeftLayout.addWidget(self.tableViewSubBockStocks) - self.myLeftLayout.addLayout(self.myLeftBottomButtonsHLayout) - self.myRightLayout.addWidget(self.txtArea) - self.setLayout(self.myRootLayout) - - ####################################################################################### - # - pass - - - def LoadDataClick(self): - - - - try: - - # self.block_list_df = QA_fetch_stock_block() - # print(self.block_list_df) - # - # blockNameList = {} - # - # self.block_list_df = self.block_list_df.set_index(['blockname']) - # for iIndex in self.block_list_df.index: - # #row = self.block_list_df.iloc(iIndex) - # #strBlockName = self.block_list_df.loc[iIndex,'blockname'] - # strBlockName = iIndex - # try: - # dict = blockNameList[strBlockName] - # dict['count'] = dict['count'] + 1 - # - # except Exception as ee: - # blockNameList[strBlockName] = 0 - # - # dictNew = {} - # dictNew['up']=0 - # dictNew['down']=0 - # dictNew['count']=0 - # dictNew['upRatio']=0.0 - # dictNew['downRation']=0.0 - # blockNameList[strBlockName] = dictNew - - - #统计上涨家数 - - thread_check_stock_block = QThread_Check_StockBlock_DB() - dlg = ProgressDlg_WithQThread(self, thread_check_stock_block,"统计板块信息","统计板块信息") - dlg.startMyThread() - dlg.exec() - - blockStatisList = thread_check_stock_block.blockStatisticList - - - self.my_model = MyTableModel(stock_block_list = blockStatisList) - self.tableViewBlock.setModel(self.my_model) - self.tableViewBlock.update() - - except Exception as ee: - errorMsg = ee.__str__() - print(errorMsg) - - #self. - # model = self.tableViewBlock.model(block_list_df) - # - # - # self.table_model(self.modelBlock) - #model.reloadDate() - #model.layoutChanged.emit() - - #self.tableViewBlock.update() - pass - - - def doStatistic(self): - pass \ No newline at end of file diff --git a/QUANTAXIS_Monitor_GUI/MainTabWindows/Tab05_StrategyBacktraceRuning.py b/QUANTAXIS_Monitor_GUI/MainTabWindows/Tab05_StrategyBacktraceRuning.py deleted file mode 100644 index 8990156d9..000000000 --- a/QUANTAXIS_Monitor_GUI/MainTabWindows/Tab05_StrategyBacktraceRuning.py +++ /dev/null @@ -1,27 +0,0 @@ -import sys -from PyQt5.QtCore import * -from PyQt5.QtGui import * -from PyQt5.QtWidgets import * -from PyQt5 import QtCore, QtGui, QtWidgets - - -class TabStrategyBacktraceRunning(QWidget): - def __init__(self, parent=None): - super(TabStrategyBacktraceRunning, self).__init__(parent) - - def initUI(self): - ''' - ---------------------------------------------------------| - | 策略目录名称 | 回测 停止 报告 | - | kdj指标策略1 |-------------------------------——-------| - | macd策略2 | * * * * | - | boll策略 | * * * | - | MA均线策略 | * * * | - | | | - --------------------------------------------------------—— - :return: - ''' - pass - - - diff --git a/QUANTAXIS_Monitor_GUI/MainTabWindows/Tab06_ForecastStockTrends.py b/QUANTAXIS_Monitor_GUI/MainTabWindows/Tab06_ForecastStockTrends.py deleted file mode 100644 index 1ad624044..000000000 --- a/QUANTAXIS_Monitor_GUI/MainTabWindows/Tab06_ForecastStockTrends.py +++ /dev/null @@ -1,263 +0,0 @@ -# coding:utf-8 -# -# The MIT License (MIT) -# -# Copyright (c) 2016-2018 yutiansut/QUANTAXIS -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in all -# copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. - - -import sys -from PyQt5.QtCore import * -from PyQt5.QtGui import * -from PyQt5.QtWidgets import * -from PyQt5 import QtCore, QtGui, QtWidgets - -from QUANTAXIS_Monitor_GUI.MainTabWindows.Tab0_RootClass import * -#from QUANTAXIS_Monitor_GUI.MyQtWidgets.QStockPriceCanvas import * -from QUANTAXIS_Monitor_GUI.MyQtWidgets.QStockPriceVolumeCanvas import * - - -from QUANTAXIS.QAFetch.QAQuery_Advance import * -from QUANTAXIS.QAFetch.QAQuery import * - -class TabForecastStockTrends(TabRootClass): - def __init__(self, parent=None): - super(TabForecastStockTrends, self).__init__(parent) - - def initUI(self): - ''' - ---------------------------------------------------------——|————————| - | 周期() 复权()坐标类型() 股票名字 代码 R是否融券标的 | top - --------------------------------------------------------——----------| - | | | - | | | - | | | - ## | 筹码分布| middle - | # | | - # | | - #### k线走势计算 B点 S点 | | - | 操作建议 | | - | | | - ———————————————————————————————————————————————————————————————————————— - | |基本财务数据| - | 成交量 | | button - ———————————————————————————————————————————————————————————| | - | 技术指标 macd | | - | | | - —————————————————————————————————————————————————————————————————————— - - - :return: - ''' - - self.comboCyc = QComboBox(self) - self.comboFQ = QComboBox(self) - self.comboCoordType = QComboBox(self) - self.editCodeName = QLineEdit(self) - self.lbCodeName = QLabel(self) - - self.bntZoomIn = QPushButton(self) - self.bntZoomOut = QPushButton(self) - - self.bntMoveLeft = QPushButton(self) - self.bntMoveRight= QPushButton(self) - - #self.stockpriceChart = QtStockPriceCanvas(self) # k线图 - - self.stockpriceChart = QtStockPriceVolumeFrame() - self.stockpriceChart.setMouseTracking(True) #跟踪鼠标操作 - self.stockpriceChart.setFocusPolicy(Qt.StrongFocus) - - #self.stockChipDistrubuteChart = QWidget(self) # 筹码分布 - - #self.volumeChart = - #self.volumeChart = QStockPriceCanvas(self) - - - self.technicalChart = QWidget(self) - self.financialChart = QWidget(self) - - # - - self.comboCyc.addItem('日线') - self.comboCyc.addItem('周线') - self.comboCyc.addItem('月线') - self.comboCyc.addItem('年线') - self.comboCyc.addItem('60分钟线') - self.comboCyc.addItem('30分钟线') - self.comboCyc.addItem('15分钟线') - self.comboCyc.addItem('5分钟线') - self.comboCyc.addItem('1分钟线') - - self.comboFQ.addItem('前复权') - self.comboFQ.addItem('后复权') - self.comboFQ.addItem('不复权') - - self.comboCoordType.addItem('对数坐标') - self.comboCoordType.addItem('算数坐标') - - self.bntMoveRight.setText("➡️") - self.bntMoveLeft.setText("⬅️️") - self.bntZoomOut.setText("🔍-") - self.bntZoomIn.setText("🔎+") - - self.bntMoveLeft.clicked.connect(self.moveLeft) - self.bntMoveRight.clicked.connect(self.moveRight) - - self.bntZoomOut.clicked.connect(self.zoomOut) - self.bntZoomIn.clicked.connect(self.zoomIn) - #self.editCodeName.setText('sh000001') - - # #self. - self.vboxRootLayout = QVBoxLayout(self) - self.vBoxTop = QHBoxLayout(self) - self.vBoxMiddle = QHBoxLayout(self) - #self.vBoxBottom = QHBoxLayout(self) - # - - self.setLayout(self.vboxRootLayout) - - self.vboxRootLayout.addLayout(self.vBoxTop) - self.vboxRootLayout.addLayout(self.vBoxMiddle) - #self.vboxRootLayout.addLayout(self.vBoxBottom) - - #self.vboxRootLayout.setSizeConstraint() - - self.vboxRootLayout.setSpacing(1) - self.vboxRootLayout.setContentsMargins(1,1,1,1) - # - self.vBoxTop.addWidget(self.comboFQ) - self.vBoxTop.addWidget(self.comboCyc) - - self.vBoxTop.addWidget(self.comboCoordType) - self.vBoxTop.addWidget(self.editCodeName) - self.vBoxTop.addWidget(self.lbCodeName) - self.vBoxTop.addWidget(self.bntZoomIn) - self.vBoxTop.addWidget(self.bntZoomOut) - self.vBoxTop.addWidget(self.bntMoveLeft) - self.vBoxTop.addWidget(self.bntMoveRight) - - self.vBoxTop.setSpacing(1) - self.vBoxTop.setContentsMargins(1,1,1,1) - - # - - self.vBoxMiddle.addWidget(self.stockpriceChart) - - self.vBoxMiddle.setSpacing(1) - self.vBoxMiddle.setContentsMargins(1,1,1,1) - - - #self.vBoxBottom.addWidget(self.volumeChart) - - #rect = QRect(0,0,300,300) - #self.vBoxBottom.setGeometry(rect) - - #self.volumeChart.setMinimumHeight(100) - #self.volumeChart.setMaximumHeight(100) - - #self.vboxRootLayout. - - #self.editCodeName.editingFinished.connect(self.code_editingFinished) - self.editCodeName.setPlaceholderText("输入股票代 sz000001 按回车加载图表") - self.editCodeName.returnPressed.connect(self.code_returnPressed) - - pass - - - - - - def showEvent(self, a0: QtGui.QShowEvent): - - self.stockpriceChart.clearAllImage() - self.stockpriceChart.drawCoordinate() - self.stockpriceChart.setFocus() - - pass - - def resizeEvent(self, a0: QtGui.QResizeEvent): - self.stockpriceChart.clearAllImage() - self.stockpriceChart.drawCoordinate() - self.stockpriceChart.setFocus() - - pass - - - def moveLeft(self): - self.stockpriceChart.moveLeftChart() - - - def moveRight(self): - - self.stockpriceChart.moveRightChart() - - def zoomIn(self): - self.stockpriceChart.zoomIn() - self.code_returnPressed() - - - def zoomOut(self): - self.stockpriceChart.zoomOut() - self.code_returnPressed() - - def code_returnPressed(self): - - try: - - txtInputed = self.editCodeName.text() - print("code return pressed %s"%txtInputed) - - #look up the stock code - strName = QA_fetch_stock_name(txtInputed) - - if strName is None: - msg = QMessageBox() - msg.setIcon(QMessageBox.Information) - msg.setText("输入的股票代码无效!😹") - msg.setInformativeText("请输入股票代码") - msg.setWindowTitle("提示:") - msg.setDetailedText("指数 sz000001 上证指数, 600003") - retval = msg.exec_() - else: - self.lbCodeName.setText(strName) - - - self.stockpriceChart.setCode(txtInputed,strName) - - #self.stockpriceChart.update() - # self.stockpriceChart.repaint() - - self.stockpriceChart.loadCodeData() - self.stockpriceChart.drawCoordinate() - self.stockpriceChart.drawKLine() - - #self.stockpriceChart.drawStockInfo() - self.update() - - except Exception as eee: - strErro = eee.__str__() - print(strErro) - - #set code - #stockpriceChart.setFQ() - #stockpriceChart.setCycle() - #stockpriceChart.setDateRange() - pass diff --git a/QUANTAXIS_Monitor_GUI/MainTabWindows/Tab0_RootClass.py b/QUANTAXIS_Monitor_GUI/MainTabWindows/Tab0_RootClass.py deleted file mode 100644 index dade6178d..000000000 --- a/QUANTAXIS_Monitor_GUI/MainTabWindows/Tab0_RootClass.py +++ /dev/null @@ -1,25 +0,0 @@ - -import sys -import os - -from PyQt5.QtCore import * -from PyQt5.QtGui import * -from PyQt5.QtWidgets import * - - -from abc import ABC, abstractmethod - -class TabRootClass(QWidget): - def __init__(self, parent=None): - super(TabRootClass, self).__init__(parent) - - @abstractmethod - def initUI(self): - pass - - - def setMediator(self, mediator): - self._mediator = mediator - - def getMediator(self): - return self._mediator \ No newline at end of file diff --git a/QUANTAXIS_Monitor_GUI/MainTabWindows/__init__.py b/QUANTAXIS_Monitor_GUI/MainTabWindows/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/QUANTAXIS_Monitor_GUI/MainTabWindows/splash_html_page/images/donation_rq.png b/QUANTAXIS_Monitor_GUI/MainTabWindows/splash_html_page/images/donation_rq.png deleted file mode 100644 index 2c5d7cdaa9880a6898802aff72932807aa3e0f66..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 54831 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 LZ>m?W;~4oLSSJs@ diff --git a/QUANTAXIS_Monitor_GUI/MainTabWindows/splash_html_page/images/quantaxis.png b/QUANTAXIS_Monitor_GUI/MainTabWindows/splash_html_page/images/quantaxis.png deleted file mode 100644 index 599d1e8b95df100495cc71db9d97185c983ac8af..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7433 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 diff --git a/QUANTAXIS_Monitor_GUI/MainTabWindows/splash_html_page/splash.html b/QUANTAXIS_Monitor_GUI/MainTabWindows/splash_html_page/splash.html deleted file mode 100644 index 8fa77036c..000000000 --- a/QUANTAXIS_Monitor_GUI/MainTabWindows/splash_html_page/splash.html +++ /dev/null @@ -1,32 +0,0 @@ - - - koko - - - -

QUANTAXIS 量化金融策略框架

-

数据爬取-清洗存储-分析回测-可视化-交易复盘的本地一站式解决方案

- 操作文档 - - - -
- -
  • Acknoledgement
  • -
    -
    - - - \ No newline at end of file diff --git a/QUANTAXIS_Monitor_GUI/MainWin.py b/QUANTAXIS_Monitor_GUI/MainWin.py deleted file mode 100644 index a4dcab79e..000000000 --- a/QUANTAXIS_Monitor_GUI/MainWin.py +++ /dev/null @@ -1,93 +0,0 @@ -# -*- coding: utf-8 -*- - -''' - GUI 实现 QuantAxis 的基本功能 - author: tauruswang - date: 2018-07-21 -''' - -import sys -from PyQt5.QtCore import * -from PyQt5.QtGui import * -from PyQt5.QtWidgets import * - -from QUANTAXIS_Monitor_GUI.AppMediator import * - - -from QUANTAXIS_Monitor_GUI.MainTabWindows.Tab00_WelcomeSplash import * - - -from QUANTAXIS_Monitor_GUI.MainTabWindows.Tab01_DataMaintenance import * -#from QUANTAXIS_Monitor_GUI.MainTabWindows.Tab02_WebpageCrawly_Old import * -from QUANTAXIS_Monitor_GUI.MainTabWindows.Tab02_WebpageEastMoneyZJLX import * -from QUANTAXIS_Monitor_GUI.MainTabWindows.Tab04_BlockStatistics import * - -from QUANTAXIS_Monitor_GUI.MainTabWindows.Tab06_ForecastStockTrends import * - -class TabDemo(QTabWidget): - def __init__(self, parent=None): - super(TabDemo, self).__init__(parent) - - self.mediator = Mediator() - - self.tab0 = TabWelcomeSplash(parent=self) - self.tab1 = TabDataMaintenance(parent=self) - - - self.tab2 = TabEastMoneyZJLX(parent=self) - self.tab2.setMediator(self.mediator) - - self.tab3 = QWidget() - self.tab4 = TabBlockStatistics(parent=self) - self.tab5 = QWidget() - - self.tab6 = TabForecastStockTrends(parent=self) - self.tab6.setMediator(self.mediator) - - self.tab7 = QWidget() - - self.addTab(self.tab0, "欢迎") - self.addTab(self.tab1, "数据下载") - self.addTab(self.tab2, "东方财富资金流向(近100天)") - self.addTab(self.tab3, "数据比对清洗") - self.addTab(self.tab4, "数据盘后分析任务") - self.addTab(self.tab5, "策略概率回测") - self.addTab(self.tab6, "近期上涨下跌股票预测") - self.addTab(self.tab7, "系统配置信息") - - self.tab0.initUI() - self.tab1.initUI() - self.tab2.initUI() - - self.tab4.initUI() - self.tab6.initUI() - - - self.setTabText(0, " 🎉 欢迎 ") - self.setTabText(1, " 🗂 数据维护 ") - self.setTabText(2, " 📑 东方财富资金流向 ") - self.setTabText(3, " 🖇 数据比对清洗 ") - self.setTabText(4, " 🔍 数据盘后分析任务 ") - self.setTabText(5, " 🎲 策略概率回测 ") - self.setTabText(6, " 📈 近期上涨下跌股票预测 ") - self.setTabText(7, " 🛠 系统配置信息 ") - - - #self.tab2UI() - #self.tab3UI() - #self.tab4UI() - self.setMinimumHeight(700) - self.setWindowTitle("QUANTAXIS MONITOR ver.0.0.0.1") - #self.setMinimumHeight(800) - #self.setMinimumWidth(1000) - #调试的方便使用 - #self.showMaximized() - - - - -if __name__ == '__main__': - app = QApplication(sys.argv) - demo = TabDemo() - demo.show() - sys.exit(app.exec_()) \ No newline at end of file diff --git a/QUANTAXIS_Monitor_GUI/MainWindow/TabDataMaintenance.py b/QUANTAXIS_Monitor_GUI/MainWindow/TabDataMaintenance.py deleted file mode 100644 index 186067977..000000000 --- a/QUANTAXIS_Monitor_GUI/MainWindow/TabDataMaintenance.py +++ /dev/null @@ -1,380 +0,0 @@ -import sys -from PyQt5.QtCore import * -from PyQt5.QtGui import * -from PyQt5.QtWidgets import * -from PyQt5 import QtCore, QtGui, QtWidgets - -from QUANTAXIS_Monitor_GUI.MainWindow.QA_Gui_DateFetch_Task import * - -#通达信pytdx 会输出消息, 一同输出到gui界面只能够 -class EmittingStream(QtCore.QObject): - textWritten = QtCore.pyqtSignal(str) # 定义一个发送str的信号 - def write(self, text): - self.textWritten.emit(str(text)) - - -class TabDataMaintenance(QWidget): - def __init__(self, parent=None): - super(TabDataMaintenance, self).__init__(parent) - - def initUI(self): - ''' - |--------------|------------| - | | | - | | | - |task list1 | log display| - |task list1 | | - |task list1 | | - |task list1 | | - |------------- |------------| - | button | - |---------------------------| - :return: - ''' - - self.setWindowIconText("获取数据任务列表") - self.setObjectName("data_maintenance") - QtCore.QMetaObject.connectSlotsByName(self) - - # 下面将print 系统输出重定向到textEdit中 - sys.stdout = EmittingStream(textWritten=self.outputWritten) - sys.stderr = EmittingStream(textWritten=self.outputWritten) - - - - self.gridLayut = QGridLayout() - self.taskListLayout = QVBoxLayout() - self.logListLayout = QVBoxLayout() - self.buttonListLayout = QHBoxLayout() - - self.gridLayut.addLayout(self.taskListLayout, 0,0) - self.gridLayut.addLayout(self.logListLayout , 0,1) - - ''' - void QGridLayout::addLayout(QLayout *layout, int row, int column, int rowSpan, int columnSpan, Qt::Alignment alignment = Qt::Alignment()) - This is an overloaded function. - This version adds the layout layout to the cell grid, spanning multiple rows/columns. - The cell will start at row, column spanning rowSpan rows and columnSpan columns. - If rowSpan and/or columnSpan is -1, then the layout will extend to the bottom and/or right edge, respectively. - ''' - self.gridLayut.addLayout(self.buttonListLayout, 1,0,1,2) - - - #🛠todo QT 报错 QWidget::setLayout: Attempting to set QLayout "" on QWidget "", which already has a layout - self.setLayout(self.gridLayut) - - self.qCheckboxWidgetList = [] - self.qProgressWidgetList = [] - self.allSubJobList = [] - - - ################################################################################################## - # 🛠todo 继承QWidget , 写一个类, 里面有 进度条, checkbox ,和绑定到线程 - - self.qCheckBoxJob01_save_stock_day = QCheckBox(self); - self.qCheckBoxJob01_save_stock_day.setText("save stock_day JOB01 日线数据 ") - self.qProgressJob01_save_stock_day = QProgressBar(self); - self.qProgressJob01_save_stock_day.setMaximum(100) - - # 🛠todo 应该有更加好的实现方式, 把progress bar 绑定到 任务对象中,这样写实在是太粗糙了。 - # 把job 对象 绑定到界面中 , 继承 QCheckBox 把相关到对象线程 和 widget 绑定。 - self.job01_save_stock_day = QA_GUI_DateFetch_SU_job01_stock_day() - self.job01_save_stock_day.trigger_new_log.connect(self.updateLoggin_job01_save_stock_day) - self.job01_save_stock_day.trigger_new_progress.connect(self.updateProgress_job01_save_stock_day) - self.job01_save_stock_day.trigger_start_task_begin.connect(self.updateUi_job_start_job0_save_stock_day) - self.job01_save_stock_day.trigger_start_task_done.connect(self.updateUi_job_done_job0_save_stock_day) - - - # 🛠todo 进一步封装 hardcode 1 2 3 不是一种好的的做法 - self.qCheckboxWidgetList.append(self.qCheckBoxJob01_save_stock_day) - self.qProgressWidgetList.append(self.qProgressJob01_save_stock_day) - self.allSubJobList.append(self.job01_save_stock_day) - - # 🛠todo 进一步封装 hardcode 1 2 3 不是一种好的的做法 - self.taskListLayout.addWidget(self.qCheckBoxJob01_save_stock_day) - self.taskListLayout.addWidget(self.qProgressJob01_save_stock_day) - ################################################################################################## - - self.qCheckBoxJob01_save_stock_week = QCheckBox(self); - self.qCheckBoxJob01_save_stock_week.setText("save stock_week JOB01 周线数据 ") - self.qProgressJob01_save_stock_week = QProgressBar(self) - - self.job01_save_stock_week = QA_GUI_DateFetch_SU_job01_stock_week() - self.job01_save_stock_week.trigger_new_log.connect(self.updateLoggin_job01_save_stock_week) - self.job01_save_stock_week.trigger_new_progress.connect(self.updateProgress_job01_save_stock_week) - self.job01_save_stock_week.trigger_start_task_begin.connect(self.updateUi_job_start_job0_save_stock_week) - self.job01_save_stock_week.trigger_start_task_done.connect(self.updateUi_job_done_job0_save_stock_week) - - self.qCheckboxWidgetList.append(self.qCheckBoxJob01_save_stock_week) - self.qProgressWidgetList.append(self.qProgressJob01_save_stock_week) - self.allSubJobList.append(self.job01_save_stock_week) - - - self.taskListLayout.addWidget(self.qCheckBoxJob01_save_stock_week) - self.taskListLayout.addWidget(self.qProgressJob01_save_stock_week) - ################################################################################################## - - self.qCheckBoxJob01_save_stock_month = QCheckBox(self) - self.qCheckBoxJob01_save_stock_month.setText("save stock_month JOB01 月线数据 ") - self.qProgressJob01_save_stock_month = QProgressBar(self) - - self.job01_save_stock_month = QA_GUI_DateFetch_SU_job01_stock_month() - self.job01_save_stock_month.trigger_new_log.connect(self.updateLoggin_job01_save_stock_month) - self.job01_save_stock_month.trigger_new_progress.connect(self.updateProgress_job01_save_stock_month) - self.job01_save_stock_month.trigger_start_task_begin.connect(self.updateUi_job_start_job0_save_stock_month) - self.job01_save_stock_month.trigger_start_task_done.connect(self.updateUi_job_done_job0_save_stock_month) - - self.qCheckboxWidgetList.append(self.qCheckBoxJob01_save_stock_month) - self.qProgressWidgetList.append(self.qProgressJob01_save_stock_month) - self.allSubJobList.append(self.job01_save_stock_month) - - - self.taskListLayout.addWidget(self.qCheckBoxJob01_save_stock_month) - self.taskListLayout.addWidget(self.qProgressJob01_save_stock_month) - ################################################################################################## - - self.qCheckBoxJob01_save_stock_year = QCheckBox(self) - self.qCheckBoxJob01_save_stock_year.setText("save stock_year JOB01 年线数据 ") - self.qProgressJob01_save_stock_year = QProgressBar(self) - - self.job01_save_stock_year = QA_GUI_DateFetch_SU_job01_stock_month() - self.job01_save_stock_year.trigger_new_log.connect(self.updateLoggin_job01_save_stock_year) - self.job01_save_stock_year.trigger_new_progress.connect(self.updateProgress_job01_save_stock_year) - self.job01_save_stock_year.trigger_start_task_begin.connect(self.updateUi_job_start_job0_save_stock_year) - self.job01_save_stock_year.trigger_start_task_done.connect(self.updateUi_job_done_job0_save_stock_year) - - self.qCheckboxWidgetList.append(self.qCheckBoxJob01_save_stock_year) - self.qProgressWidgetList.append(self.qProgressJob01_save_stock_year) - self.allSubJobList.append(self.job01_save_stock_year) - - - self.taskListLayout.addWidget(self.qCheckBoxJob01_save_stock_year) - self.taskListLayout.addWidget(self.qProgressJob01_save_stock_year) - ################################################################################################## - - - self.selectedSubTask = QA_GUI_Selected_TaskQueue() - self.selectedSubTask.trigger_all_task_start.connect(self.uiAllTaskStart) - self.selectedSubTask.trigger_all_task_done.connect(self.uiAllTaskDone) - - ################################################################################################## - # 🛠todo 日志显示,用table list 加入搜索的功能, 行号等, 彩色显示 - self.logDisplay = QTextEdit(self) - self.logDisplay.setObjectName("textEdit") - #self.logDisplay.setEnabled(False) - self.logDisplay.setReadOnly(True) - self.logDisplay.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOn) - self.logListLayout.addWidget(self.logDisplay) - - self.bntExecute = QPushButton(self) - self.bntExecute.setText("执行选中的任务 🐌") - self.buttonListLayout.addWidget(self.bntExecute) - - # 🛠todo 没有实现! - self.bntStopTack = QPushButton(self) - self.bntStopTack.setText("停止执行任务 🚫") - self.buttonListLayout.addWidget(self.bntStopTack) - - - self.bntClearLog = QPushButton(self) - self.bntClearLog.setText("清除日志 🗑") - self.buttonListLayout.addWidget(self.bntClearLog) - - - self.bntExecute.clicked.connect(self.doSelectedTask) - - self.bntStopTack.clicked.connect(self.doStopTask) - - # layout = QFormLayout() - # layout.setLabelAlignment(Qt.AlignLeft) - # layout.addRow("保存日线数据 ", QProgressBar(self)) - # layout.addRow("保存日除权出息数据 ", QProgressBar(self)) - # layout.addRow("保存分钟线数据", QProgressBar(self)) - # layout.addRow("保存指数数据", QProgressBar(self)) - # - # layout.addRow("保存指数线数据 ", QProgressBar(self)) - # layout.addRow("保存ETF日线数据 ", QProgressBar(self)) - # layout.addRow("保存ET分钟数据", QProgressBar(self)) - # layout.addRow("保存股票列表", QProgressBar(self)) - # layout.addRow("保存板块", QProgressBar(self)) - # layout.addRow("保存tushare数据接口获取的股票列表", QProgressBar(self)) - # layout.addRow("保存高级财务数据(自1996年开始)", QProgressBar(self)) - # layout.addRow("保存50ETF期权日线数据(不包括已经摘牌的数据)", QProgressBar(self)) - # - # qPushBnt = QPushButton(self); - # qPushBnt.setText("开始执行") - # layout.addRow("选中需要执行的任务", qPushBnt) - - # 为这个tab命名显示出来,第一个参数是哪个标签,第二个参数是标签的名字 - # 在标签1中添加这个帧布局 - - - # 接收信号str的信号槽 - def outputWritten(self, text): - cursor = self.logDisplay.textCursor() - cursor.movePosition(QtGui.QTextCursor.End) - cursor.insertText(text) - self.logDisplay.setTextCursor(cursor) - self.logDisplay.ensureCursorVisible() - - - def doSelectedTask(self): - #print("^ 准备执行选中的任务 ^") - - self.selectedSubTask.clearTask() - - # 🛠todo 需要一个总的线程队列按顺序执行 每个任务 - for itaskIndex in range(len(self.qCheckboxWidgetList)): - if self.qCheckboxWidgetList[itaskIndex].isChecked(): - self.selectedSubTask.putTask(self.allSubJobList[itaskIndex]) - - - if len(self.selectedSubTask.QA_GUI_Task_List) == 0: - msg = QMessageBox() - msg.setIcon(QMessageBox.Information) - msg.setText("至少选中一个需要执行的任务!😹") - msg.setInformativeText("至少选中一个需要执行的任务") - msg.setWindowTitle("提示:") - msg.setDetailedText("操作提示: 请选勾选中需要执行的任务") - retval = msg.exec_() - return - - - #if self.qCheckBoxJob01_save_stock_day.isChecked(): - # self.job01_save_stock_day.start() - self.selectedSubTask.start() - - pass - - def doStopTask(self): - msg = QMessageBox() - msg.setIcon(QMessageBox.Information) - msg.setText("耐心是一种美德, 耐心等等结束哈!😹 ") - msg.setInformativeText("耐心是一种美德, 耐心等等结束哈😹 ") - msg.setWindowTitle("提示:") - msg.setDetailedText("操作提示: 其实是懒,不高兴去停止线程,怕有副作用,把数据库给搞坏了") - retval = msg.exec_() - - - - ################################################################################################## - # 🛠todo 进一步封装 hardcode 1 2 3 不是一种好的的做法 - def updateUi_job_start_job0_save_stock_day(self, info_str): - - palette = self.qCheckBoxJob01_save_stock_day.palette() - palette.setColor(QPalette.Active,QPalette.WindowText, QtCore.Qt.red) - self.qCheckBoxJob01_save_stock_day.setPalette(palette) - - pass - - def updateUi_job_done_job0_save_stock_day(self, info_str): - # - palette = self.qCheckBoxJob01_save_stock_day.palette() - palette.setColor(QPalette.Active,QPalette.WindowText, QtCore.Qt.black) - self.qCheckBoxJob01_save_stock_day.setPalette(palette) - - #self.qProgressJob01_save_stock_day.setValue(0) - pass - - - def updateLoggin_job01_save_stock_day(self, log): - #print("append task log emite triggered!", log); - self.logDisplay.append(log) - - def updateProgress_job01_save_stock_day(self, progress): - #print('update task progress ', progress); - self.qProgressJob01_save_stock_day.setValue(progress) - - ################################################################################################## - - def updateUi_job_start_job0_save_stock_week(self, info_str): - - palette = self.qCheckBoxJob01_save_stock_week.palette() - palette.setColor(QPalette.Active,QPalette.WindowText, QtCore.Qt.red) - self.qCheckBoxJob01_save_stock_week.setPalette(palette) - - - pass - - def updateUi_job_done_job0_save_stock_week(self, info_str): - # - palette = self.qCheckBoxJob01_save_stock_week.palette() - palette.setColor(QPalette.Active,QPalette.WindowText, QtCore.Qt.black) - self.qCheckBoxJob01_save_stock_week.setPalette(palette) - - #self.qProgressJob01_save_stock_day.setValue(0) - pass - - - def updateLoggin_job01_save_stock_week(self, log): - #print("append task log emite triggered!", log); - self.logDisplay.append(log) - - def updateProgress_job01_save_stock_week(self, progress): - #print('update task progress ', progress); - self.qProgressJob01_save_stock_week.setValue(progress) - - ################################################################################################## - - def updateUi_job_start_job0_save_stock_month(self, info_str): - - palette = self.qCheckBoxJob01_save_stock_month.palette() - palette.setColor(QPalette.Active,QPalette.WindowText, QtCore.Qt.red) - self.qCheckBoxJob01_save_stock_month.setPalette(palette) - - pass - - def updateUi_job_done_job0_save_stock_month(self, info_str): - # - palette = self.qCheckBoxJob01_save_stock_month.palette() - palette.setColor(QPalette.Active,QPalette.WindowText, QtCore.Qt.black) - self.qCheckBoxJob01_save_stock_month.setPalette(palette) - - #self.qProgressJob01_save_stock_day.setValue(0) - pass - - - def updateLoggin_job01_save_stock_month(self, log): - #print("append task log emite triggered!", log); - self.logDisplay.append(log) - - def updateProgress_job01_save_stock_month(self, progress): - #print('update task progress ', progress); - self.qProgressJob01_save_stock_month.setValue(progress) - - ################################################################################################## - - def updateUi_job_start_job0_save_stock_year(self, info_str): - - palette = self.qCheckBoxJob01_save_stock_year.palette() - palette.setColor(QPalette.Active, QPalette.WindowText, QtCore.Qt.red) - self.qCheckBoxJob01_save_stock_year.setPalette(palette) - - pass - - def updateUi_job_done_job0_save_stock_year(self, info_str): - # - palette = self.qCheckBoxJob01_save_stock_year.palette() - palette.setColor(QPalette.Active, QPalette.WindowText, QtCore.Qt.black) - self.qCheckBoxJob01_save_stock_year.setPalette(palette) - - # self.qProgressJob01_save_stock_day.setValue(0) - pass - - def updateLoggin_job01_save_stock_year(self, log): - # print("append task log emite triggered!", log); - self.logDisplay.append(log) - - def updateProgress_job01_save_stock_year(self, progress): - # print('update task progress ', progress); - self.qProgressJob01_save_stock_year.setValue(progress) - - ################################################################################################## - - def uiAllTaskStart(self, logInfo): - self.bntExecute.setEnabled(False) - pass - - def uiAllTaskDone(self, logInfo): - self.bntExecute.setEnabled(True) - pass \ No newline at end of file diff --git a/QUANTAXIS_Monitor_GUI/MyQtWidgets/MyDrawImgs/QStockDateRuler.py b/QUANTAXIS_Monitor_GUI/MyQtWidgets/MyDrawImgs/QStockDateRuler.py deleted file mode 100644 index a7d86f3a7..000000000 --- a/QUANTAXIS_Monitor_GUI/MyQtWidgets/MyDrawImgs/QStockDateRuler.py +++ /dev/null @@ -1,228 +0,0 @@ -from PyQt5.Qt import QLabel -from PyQt5.Qt import QDialog -from PyQt5.Qt import QMessageBox -from PyQt5.Qt import QHBoxLayout -from PyQt5.Qt import * -from PyQt5.QtGui import * -from PyQt5.QtCore import * - -import math - -from typing import List - -import numpy as np - - -class CanvasBottomDateRuler: - def __init__(self): - self.myCanvasDateRuler = QImage() - - #放大缩小使用 - #默认100天 - self.showDayInGauges = 100 - self.showWeekInGauges = 100 - self.showMonthInGauges = 100 - - - self.tradeDayList = [] - self.height = 18 - - self.parentHeight = 0 - self.parentWidth = 0 - - - self.mouseX = 0 - self.currentPosGap = -1 - - pass - - def setDrawImageSize(self, rect: QRect): - self.myCanvasDateRuler = QImage(rect, QImage.Format_ARGB32) - self.myCanvasDateRuler.fill(QColor.fromRgb(0, 0, 0, 0)) - - self.parentWidth = self.myCanvasDateRuler.width() - self.parentHeight = self.myCanvasDateRuler.height() - - pass - - def clearImage(self): - painter = QPainter(self.myCanvasDateRuler) - - h = self.myCanvasDateRuler.height() - w = self.myCanvasDateRuler.width() - painter.fillRect(0,0,w,h, QColor.fromRgb(0,0,0,0)) - - self.myCanvasDateRuler.fill(QColor.fromRgb(0, 0, 0, 0)) - - - - #self.myCanvasDateRuler. - - - def getMouseGridIndex(self, mousex:float): - try: - h = self.myCanvasDateRuler.height() - w = self.myCanvasDateRuler.width() - - - guageWidth = float(w) / self.showDayInGauges - self.mouseX = mousex - self.currentPosGap = math.floor(mousex / guageWidth) - - return self.currentPosGap - - except Exception as eee: - strError = eee.__str__() - print(strError) - - - # mouse grid-snap in day - def getMoseGapPosX(self, mousex: float): - try: - h = self.myCanvasDateRuler.height() - w = self.myCanvasDateRuler.width() - - - guageWidth = float(w) / self.showDayInGauges - - self.mouseX = mousex - self.currentPosGap = math.floor(mousex / guageWidth) - - print("currentPosGap ", self.currentPosGap) - - x = self.currentPosGap*guageWidth + guageWidth/2 - return x - - except Exception as eee: - strError = eee.__str__() - print(strError) - - def getMouseMouseDateStr(self,mousex: float): - - try: - #h = self.myCanvasDateRuler.height() - w = self.myCanvasDateRuler.width() - - guageWidth = w / self.showDayInGauges - - self.mouseX = mousex - self.currentPosGap = math.floor(mousex / guageWidth) - - sizeOfLoadTradeDayList = len(self.tradeDayList) - - if sizeOfLoadTradeDayList - self.showDayInGauges >= 0: - strDay = self.tradeDayList[self.showDayInGauges - self.currentPosGap - 1] - - else: - - if sizeOfLoadTradeDayList - self.currentPosGap > 0: - strDay = self.tradeDayList[sizeOfLoadTradeDayList - self.currentPosGap - 1] - - return strDay - - - - except Exception as eee: - strError = eee.__str__() - print(strError) - - def drawSelectedDay(self,positionx :float): - try: - h = self.myCanvasDateRuler.height() - w = self.myCanvasDateRuler.width() - painter = QPainter(self.myCanvasDateRuler) - - - guageWidth = w / self.showDayInGauges - - #painter.fillRect(positionx - guageWidth/2, 0, guageWidth , h/4, QColor.fromRgb(125,125,0)) - - except Exception as eee: - strError = eee.__str__() - print(strError) - - - def draw(self): - - try: - - h = self.myCanvasDateRuler.height() - w = self.myCanvasDateRuler.width() - - self.myCanvasDateRuler.fill(QColor.fromRgb(0, 0, 0, 0)) - - painter = QPainter(self.myCanvasDateRuler) - - #painter.fillRect(0, 0, w, h, QColor.fromRgb(255, 255, 255, 255)) - - guageWidth = w / self.showDayInGauges - - for iIndex in range(self.showDayInGauges): - - rectGuage = QRectF(iIndex * guageWidth, 0, guageWidth, h/4) - #painter.fillRect(rectGuage,QColor.fromRgb(127,127,255,0)) - - painter.drawRect(rectGuage) - - # if iIndex == self.currentPosGap: - # painter.fillRect(rectGuage,QColor.fromRgb(0,128,128)) - - sizeOfLoadTradeDayList = len(self.tradeDayList) - - if iIndex % 20 == 0 and sizeOfLoadTradeDayList > 0: - strDay = "" - p = QPoint(iIndex * guageWidth, h/4 *3 +2) - - if (sizeOfLoadTradeDayList - self.showDayInGauges) >= 0: - - painter.drawText(p, strDay1) - painter.fillRect(rectGuage, QColor.fromRgb(128,11,11)) - - - - else: - - if (sizeOfLoadTradeDayList - iIndex) > 0: - strDay1 = self.tradeDayList[sizeOfLoadTradeDayList - iIndex -1] - painter.drawText(p, strDay1) - painter.fillRect(rectGuage, QColor.fromRgb(128, 111, 11)) - - #painter.fillRect(rectGuage, QColor.fromRgb(100, 100, 100)) - print("ok") - - - except Exception as eee: - strError = eee.__str__() - print(strError) - - - def setShowDays(self, showDays : int): - - - pass - - def setTradeWeekList(self, tradeDateList: List[str], showWeeks : int): - - pass - - def setTradeMonthList(self, tradeWeekList: List[str], showMonths : int): - - pass - - def setTradeDayList(self, tradeDateList: List[str], showDay : int): - - self.tradeDayList = tradeDateList - self.showDayInGauges = showDay - pass - - - - sizeOfDate = len(tradeDateList) - - # 往后计算 - #if sizeOfDate < showDaysCount: - - - - - pass \ No newline at end of file diff --git a/QUANTAXIS_Monitor_GUI/MyQtWidgets/MyDrawImgs/QStockGMMA.py b/QUANTAXIS_Monitor_GUI/MyQtWidgets/MyDrawImgs/QStockGMMA.py deleted file mode 100644 index fd765fb33..000000000 --- a/QUANTAXIS_Monitor_GUI/MyQtWidgets/MyDrawImgs/QStockGMMA.py +++ /dev/null @@ -1,415 +0,0 @@ -from PyQt5.Qt import QLabel -from PyQt5.Qt import QDialog -from PyQt5.Qt import QMessageBox -from PyQt5.Qt import QHBoxLayout -from PyQt5.Qt import * -from PyQt5.QtGui import * -from PyQt5.QtCore import * - - -from typing import List - -import math -import numpy as np - - -from QUANTAXIS.QAUtil.QADate import * -from QUANTAXIS.QAUtil.QADate_trade import * - -from QUANTAXIS.QAFetch.QAQuery_Advance import * - -from QUANTAXIS.QAIndicator import QA_indicator_MA - - - -''' -顾比复合移动平均线(GuppyMultipleMovingAverAge,GMMA)。 -GMMA使用了两组指数移动平均数进行分析。由3、5、8、10、12和15日移动平均线构成一组“短期组”, -这组指标透露了市场短期投机者的行为;而“长期组”则由30、35、40、45、50和60日移动平均线构成 -''' -class CanvasGMMA: - def __init__(self): - self.myCanvasGMMA = QImage() - - mouseX = 0.0 - mouseY = 0.0 - - xInGrid = 0.0 - self.showDayInGauges = 100 - - - pass - - def setDrawImageSize(self, rect: QRect): - self.myCanvasGMMA = QImage(rect, QImage.Format_ARGB32) - self.myCanvasGMMA.fill(QColor.fromRgb(0, 0, 0, 0)) - pass - - - def draw(self): - - try: - self.myCanvasGMMA.fill(QColor.fromRgb(0, 0, 0, 0)) - - h = self.myCanvasGMMA.height() - w = self.myCanvasGMMA.width() - painter = QPainter(self.myCanvasGMMA) - - qp = QPoint(10,10) - strMsg = "%s"%("Guppy Multiple Moving Average Lines") - painter.drawText(qp,strMsg) - - kLineDayWidth = w / self.showDayInGauges - - painter.save() - - pen = QPen(); - pen.setStyle(Qt.SolidLine) - pen.setBrush(QBrush(Qt.blue)); # 设置笔刷, - - painter.setPen(pen) - - for iIndex in range(self.showDayInGauges-1): - if iIndex < len(self.pointsY_Ma03) and iIndex+1 < len(self.pointsY_Ma03): - painter.drawLine(iIndex *kLineDayWidth, self.pointsY_Ma03[iIndex], \ - iIndex*kLineDayWidth + kLineDayWidth, self.pointsY_Ma03[iIndex+1]) - - # - if iIndex < len(self.pointsY_Ma05) and iIndex+1 < len(self.pointsY_Ma05): - painter.drawLine(iIndex * kLineDayWidth, self.pointsY_Ma05[iIndex], \ - iIndex * kLineDayWidth + kLineDayWidth, self.pointsY_Ma05[iIndex + 1]) - - if iIndex < len(self.pointsY_Ma08) and iIndex + 1 < len(self.pointsY_Ma08): - painter.drawLine(iIndex * kLineDayWidth, self.pointsY_Ma08[iIndex], \ - iIndex * kLineDayWidth + kLineDayWidth, self.pointsY_Ma08[iIndex + 1]) - - if iIndex < len(self.pointsY_Ma10) and iIndex + 1 < len(self.pointsY_Ma10): - painter.drawLine(iIndex * kLineDayWidth, self.pointsY_Ma10[iIndex], \ - iIndex * kLineDayWidth + kLineDayWidth, self.pointsY_Ma10[iIndex + 1]) - - if iIndex < len(self.pointsY_Ma12) and iIndex + 1 < len(self.pointsY_Ma12): - painter.drawLine(iIndex * kLineDayWidth, self.pointsY_Ma12[iIndex], \ - iIndex * kLineDayWidth + kLineDayWidth, self.pointsY_Ma12[iIndex + 1]) - - #ppp = QPoint((iIndex * kLineDayWidth), (self.pointsY_Ma12[iIndex])+20) - - if iIndex < len(self.pointsY_Ma15) and iIndex + 1 < len(self.pointsY_Ma15): - painter.drawLine(iIndex * kLineDayWidth, self.pointsY_Ma15[iIndex], \ - iIndex * kLineDayWidth + kLineDayWidth, self.pointsY_Ma15[iIndex + 1]) - - - - - painter.restore() - - pen = QPen(); - pen.setStyle(Qt.SolidLine) - pen.setBrush(QBrush(Qt.red)); # 设置笔刷, - - painter.setPen(pen) - - painter.save() - - - currentState = 0 - previousState = 0 - - - for iIndex in range(self.showDayInGauges - 1): - if iIndex < len(self.pointsY_Ma30) and iIndex + 1 < len(self.pointsY_Ma30): - painter.drawLine(iIndex * kLineDayWidth, self.pointsY_Ma30[iIndex], \ - iIndex * kLineDayWidth + kLineDayWidth, self.pointsY_Ma30[iIndex + 1]) - ppp = QPoint((iIndex * kLineDayWidth), (self.pointsY_Ma30[iIndex]) + 20) - - if iIndex < len(self.pointsY_Ma35) and iIndex + 1 < len(self.pointsY_Ma35): - painter.drawLine(iIndex * kLineDayWidth, self.pointsY_Ma35[iIndex], \ - iIndex * kLineDayWidth + kLineDayWidth, self.pointsY_Ma35[iIndex + 1]) - - if iIndex < len(self.pointsY_Ma40) and iIndex + 1 < len(self.pointsY_Ma40): - painter.drawLine(iIndex * kLineDayWidth, self.pointsY_Ma40[iIndex], \ - iIndex * kLineDayWidth + kLineDayWidth, self.pointsY_Ma40[iIndex + 1]) - - if iIndex < len(self.pointsY_Ma45) and iIndex + 1 < len(self.pointsY_Ma45): - painter.drawLine(iIndex * kLineDayWidth, self.pointsY_Ma45[iIndex], \ - iIndex * kLineDayWidth + kLineDayWidth, self.pointsY_Ma45[iIndex + 1]) - - if iIndex < len(self.pointsY_Ma50) and iIndex + 1 < len(self.pointsY_Ma50): - painter.drawLine(iIndex * kLineDayWidth, self.pointsY_Ma50[iIndex], \ - iIndex * kLineDayWidth + kLineDayWidth, self.pointsY_Ma50[iIndex + 1]) - - ppp = QPoint((iIndex * kLineDayWidth), (self.pointsY_Ma50[iIndex])+20) - - - if iIndex < len(self.pointsY_Ma60) and iIndex + 1 < len(self.pointsY_Ma60): - painter.drawLine(iIndex * kLineDayWidth, self.pointsY_Ma60[iIndex], \ - iIndex * kLineDayWidth + kLineDayWidth, self.pointsY_Ma60[iIndex + 1]) - - - - if iIndex < len(self.pointsY_Ma30) and iIndex + 1 < len(self.pointsY_Ma30) and \ - iIndex < len(self.pointsY_Ma35) and iIndex + 1 < len(self.pointsY_Ma35) and \ - iIndex < len(self.pointsY_Ma40) and iIndex + 1 < len(self.pointsY_Ma40) and \ - iIndex < len(self.pointsY_Ma45) and iIndex + 1 < len(self.pointsY_Ma45) and \ - iIndex < len(self.pointsY_Ma50) and iIndex + 1 < len(self.pointsY_Ma50): - - if self.pointsY_Ma30[iIndex] < self.pointsY_Ma35[iIndex] and \ - self.pointsY_Ma35[iIndex] < self.pointsY_Ma40[iIndex]: - #self.pointsY_Ma40[iIndex] < self.pointsY_Ma45[iIndex] and \ - #self.pointsY_Ma45[iIndex] < self.pointsY_Ma50[iIndex]: - - if currentState == 0 or currentState == previousState or currentState == 2: - previousState = currentState - currentState = 1 - - elif self.pointsY_Ma30[iIndex] > self.pointsY_Ma35[iIndex] and \ - self.pointsY_Ma35[iIndex] > self.pointsY_Ma40[iIndex]: - # self.pointsY_Ma40[iIndex] > self.pointsY_Ma45[iIndex] and \ - # self.pointsY_Ma45[iIndex] > self.pointsY_Ma50[iIndex]: - - if currentState == 0 or currentState == previousState or currentState == 1: - previousState = currentState - currentState = 2 - - if previousState != currentState: - if previousState == 1 and currentState == 2: - # painter.drawText(ppp, "卖出") - # painter.drawLine((ppp.x()), 0, (ppp.x()), 1000) - painter.fillRect(ppp.x(), 0, kLineDayWidth, 1000, QColor(0, 255, 0, 88)) - elif previousState == 2 and currentState == 1: - # painter.drawText(ppp, "买入") - # painter.drawLine((ppp.x()), 0, (ppp.x()), 1000) - painter.fillRect(ppp.x(), 0, kLineDayWidth, 1000, QColor(255, 0, 0, 88)) - else: - print("current state is %d %d" % (currentState, previousState)) - - else: - print("current statis is equal %d %d" % (currentState, previousState)) - - - - painter.restore() - - - - - pass - - except Exception as eee: - strError = eee.__str__() - print(strError) - - - pass - - def clearImage(self): - painter = QPainter(self.myCanvasGMMA) - h = self.myCanvasGMMA.height() - w = self.myCanvasGMMA.width() - painter.fillRect(0, 0, w, h, QColor.fromRgb(0, 0, 0, 0)) - - - def setPriceRange(self, highPrice, lowPrice): - self.highestPriceInScreen = highPrice - self.lowestPriceInScreen = lowPrice - - def setTradeDays(self, tradeDateList: List[str]): - self.tradeDateList = tradeDateList - pass - - - - # pointsY_Ma03 = [] - # def set03MA(self, ma03_DataFrame: pd.DataFrame, showDays: int): - # - # h = self.myCanvasGMMA.height() - # w = self.myCanvasGMMA.width() - # - # #self.ma03_DataFrame = ma03_DataFrame - # self.showDayInGauges = showDays - # - # priceRange = self.highestPriceInScreen - self.lowestPriceInScreen - # priceGapCount = priceRange * 100 - # pricePerGapHeight = h / priceGapCount - # - # iIndex = 0 - # self.pointsY_Ma03.clear() - # for row in ma03_DataFrame.iterrows(): - # - # strTimeOfTradeDayMa = str(row[0][0])[:10] - # - # if np.isnan(row[1][0]): - # continue - # else: - # if strTimeOfTradeDayMa in self.tradeDateList: - # heightFromMinPriceOpen = (row[1][0] - self.lowestPriceInScreen) * (100) * pricePerGapHeight - # heihgtFromMaxPriceOpen = h - heightFromMinPriceOpen - # Ma03_ScreenCoorY = 0 + heihgtFromMaxPriceOpen - # self.pointsY_Ma03.append(Ma03_ScreenCoorY) - # iIndex = iIndex + 1 - # - # - # - # - # pointsY_Ma05 = [] - # def set05MA(self, ma05_DataFrame: pd.DataFrame, showDays :int): - # - # h = self.myCanvasGMMA.height() - # w = self.myCanvasGMMA.width() - # - # #self.ma05_DataFrame = ma05_DataFrame - # self.showDayInGauges = showDays - # - # priceRange = self.highestPriceInScreen - self.lowestPriceInScreen - # priceGapCount = priceRange * 100 - # pricePerGapHeight = h / priceGapCount - # - # iIndex = 0 - # self.pointsY_Ma05.clear() - # for row in ma05_DataFrame.iterrows(): - # - # strTimeOfTradeDayMa = str(row[0][0])[:10] - # - # if np.isnan(row[1][0]): - # continue - # else: - # if strTimeOfTradeDayMa in self.tradeDateList: - # heightFromMinPriceOpen = (row[1][0] - self.lowestPriceInScreen) * (100) * pricePerGapHeight - # heihgtFromMaxPriceOpen = h - heightFromMinPriceOpen - # Ma05_ScreenCoorY = 0 + heihgtFromMaxPriceOpen - # self.pointsY_Ma05.append(Ma05_ScreenCoorY) - # iIndex = iIndex + 1 - # - # pointsY_Ma08 = [] - # def set08MA(self, ma08_DataFrame: pd.DataFrame, showDays: int): - # - # h = self.myCanvasGMMA.height() - # w = self.myCanvasGMMA.width() - # - # # self.ma05_DataFrame = ma05_DataFrame - # self.showDayInGauges = showDays - # - # priceRange = self.highestPriceInScreen - self.lowestPriceInScreen - # priceGapCount = priceRange * 100 - # pricePerGapHeight = h / priceGapCount - # - # iIndex = 0 - # self.pointsY_Ma08.clear() - # for row in ma08_DataFrame.iterrows(): - # - # strTimeOfTradeDayMa = str(row[0][0])[:10] - # - # if np.isnan(row[1][0]): - # continue - # else: - # if strTimeOfTradeDayMa in self.tradeDateList: - # heightFromMinPriceOpen = (row[1][0] - self.lowestPriceInScreen) * (100) * pricePerGapHeight - # heihgtFromMaxPriceOpen = h - heightFromMinPriceOpen - # Ma08_ScreenCoorY = 0 + heihgtFromMaxPriceOpen - # self.pointsY_Ma08.append(Ma08_ScreenCoorY) - # iIndex = iIndex + 1 - # - def setXMA(self, maX_DataFrame: pd.DataFrame, showDays: int): - - h = self.myCanvasGMMA.height() - w = self.myCanvasGMMA.width() - - # self.ma05_DataFrame = ma05_DataFrame - self.showDayInGauges = showDays - - priceRange = self.highestPriceInScreen - self.lowestPriceInScreen - priceGapCount = priceRange * 100 - pricePerGapHeight = h / priceGapCount - - iIndex = 0 - pointsY_MaX = [] - pointsY_MaX.clear() - for row in maX_DataFrame.iterrows(): - - strTimeOfTradeDayMa = str(row[0][0])[:10] - - if np.isnan(row[1][0]): - continue - else: - if strTimeOfTradeDayMa in self.tradeDateList: - heightFromMinPriceOpen = (row[1][0] - self.lowestPriceInScreen) * (100) * pricePerGapHeight - heihgtFromMaxPriceOpen = h - heightFromMinPriceOpen - MaX_ScreenCoorY = 0 + heihgtFromMaxPriceOpen - pointsY_MaX.append(MaX_ScreenCoorY) - iIndex = iIndex + 1 - - return pointsY_MaX - - pointsY_Ma03 = [] - def set03MA(self, ma03_DataFrame: pd.DataFrame, showDays: int): - self.pointsY_Ma03 = self.setXMA(ma03_DataFrame, showDays) - - pointsY_Ma05 = [] - def set05MA(self, ma05_DataFrame: pd.DataFrame, showDays: int): - self.pointsY_Ma05 = self.setXMA(ma05_DataFrame, showDays) - - pointsY_Ma08 = [] - def set08MA(self, ma08_DataFrame: pd.DataFrame, showDays: int): - self.pointsY_Ma08 = self.setXMA(ma08_DataFrame, showDays) - - pointsY_Ma10 = [] - def set10MA(self, ma10_DataFrame: pd.DataFrame, showDays: int): - self.pointsY_Ma10 = self.setXMA(ma10_DataFrame, showDays) - - pointsY_Ma12 = [] - def set12MA(self, ma12_DataFrame: pd.DataFrame, showDays: int): - self.pointsY_Ma12 = self.setXMA(ma12_DataFrame, showDays) - - pointsY_Ma15 = [] - def set15MA(self, ma15_DataFrame: pd.DataFrame, showDays: int): - self.pointsY_Ma15 = self.setXMA(ma15_DataFrame, showDays) - - # 30、35、40、45、50 和60 - - pointsY_Ma30 = [] - def set30MA(self, ma30_DataFrame: pd.DataFrame, showDays: int): - self.pointsY_Ma30 = self.setXMA(ma30_DataFrame, showDays) - - pointsY_Ma35 = [] - def set35MA(self, ma35_DataFrame: pd.DataFrame, showDays: int): - self.pointsY_Ma35 = self.setXMA(ma35_DataFrame, showDays) - - pointsY_Ma40 = [] - def set40MA(self, ma40_DataFrame: pd.DataFrame, showDays: int): - self.pointsY_Ma40 = self.setXMA(ma40_DataFrame, showDays) - - pointsY_Ma45 = [] - def set45MA(self, ma45_DataFrame: pd.DataFrame, showDays: int): - self.pointsY_Ma45 = self.setXMA(ma45_DataFrame, showDays) - - pointsY_Ma50 = [] - def set50MA(self, ma50_DataFrame: pd.DataFrame, showDays: int): - self.pointsY_Ma50 = self.setXMA(ma50_DataFrame, showDays) - - pointsY_Ma60 = [] - def set60MA(self, ma60_DataFrame: pd.DataFrame, showDays: int): - self.pointsY_Ma60 = self.setXMA(ma60_DataFrame, showDays) - - # def setTradeDayListAndOCLH(self, tradeDateList: List[str], oclhList :np.ndarray, - # highestPriceInScreen: float, lowestPriceInScreen : float, showDay : int): - # - # - # #self.oclhList = oclhList[::-1] - # # self.oclhList = oclhList - # # self.tradeDayList = tradeDateList - # # self.defaultShowDay = showDay - # # - # # self.lowestPriceInScreen = lowestPriceInScreen - # # self.highestPriceInScreen = highestPriceInScreen - - def getMousePositionPrice(self,xInGrid: int): - if self.oclhList is not None and xInGrid < len(self.oclhList): - # openP = self.oclhList[xInGrid][0] - # closeP = self.oclhList[xInGrid][1] - # lowP = self.oclhList[xInGrid][2] - # highP = self.oclhList[xInGrid][3] - # - # return [openP, closeP, lowP, highP] - return None - else: - return None - pass diff --git a/QUANTAXIS_Monitor_GUI/MyQtWidgets/MyDrawImgs/QStockInfo.py b/QUANTAXIS_Monitor_GUI/MyQtWidgets/MyDrawImgs/QStockInfo.py deleted file mode 100644 index 04725ee44..000000000 --- a/QUANTAXIS_Monitor_GUI/MyQtWidgets/MyDrawImgs/QStockInfo.py +++ /dev/null @@ -1,92 +0,0 @@ - -from PyQt5.Qt import QLabel -from PyQt5.Qt import QDialog -from PyQt5.Qt import QMessageBox -from PyQt5.Qt import QHBoxLayout -from PyQt5.Qt import * -from PyQt5.QtGui import * -from PyQt5.QtCore import * - -import math - -from typing import List - -import numpy as np - - -class CanvasStockInfo: - def __init__(self): - self.myCanvasStockInfo = QImage() - self.height = 80 - - def setDrawImageSize(self,rect:QRect): - self.myCanvasStockInfo = QImage(rect, QImage.Format_ARGB32) - self.myCanvasStockInfo.fill(QColor.fromRgb(0, 0, 0, 0)) - - self.parentWidth = self.myCanvasStockInfo.width() - self.parentHeight = self.myCanvasStockInfo.height() - pass - - def clearImage(self): - painter = QPainter(self.myCanvasStockInfo) - - h = self.myCanvasStockInfo.height() - w = self.myCanvasStockInfo.width() - painter.fillRect(0,0,w,h, QColor.fromRgb(0,0,0,0)) - - self.myCanvasStockInfo.fill(QColor.fromRgb(0, 0, 0, 0)) - - strName = None - strCode = None - - - strCurrentDate = "" - strCurrentPrice = "" - def setCodeAndName(self, strName: str, strCode: str): - self.strName = strName - self.strCode = strCode - pass - - def setMouseMoveDate(self, strCurrentDate :str): - self.strCurrentDate = strCurrentDate - pass - - - def setMouseMovePrice(self, oclh: List[float]): - self.oclh = oclh - pass - - def setMousePositionInfo(self, xpos: float, ypos: float): - self.xpos = xpos - self.ypos = ypos - - def draw(self): - self.myCanvasStockInfo.fill(QColor.fromRgb(0, 0, 0, 0)) - - h = self.myCanvasStockInfo.height() - w = self.myCanvasStockInfo.width() - painter = QPainter(self.myCanvasStockInfo) - - painter.fillRect(0, 0, w, h, QColor.fromRgb(200, 200, 199, 255)) - - if self.strName is not None and self.strCode is not None: - pq = QPoint(0,10) - str = "%s %s"%(self.strName, self.strCode) - painter.drawText(pq, str) - - if self.strCurrentDate is not None: - pq = QPoint(100, 10) - str = "%s %s" % (self.strCurrentPrice, self.strCurrentDate) - painter.drawText(pq, str) - - if self.oclh is not None: - pq = QPoint(200,10) - str = "开盘价%0.2f 收盘价%0.2f 最低价%0.2f 最高价%0.2f" % (self.oclh[0], self.oclh[1], self.oclh[2], self.oclh[3]) - painter.drawText(pq, str) - - if self.xpos is not None and self.ypos is not None: - pq = QPoint(200, 200) - str = "%f, %f" % (self.xpos , self.ypos) - painter.drawText(pq, str) - - pass \ No newline at end of file diff --git a/QUANTAXIS_Monitor_GUI/MyQtWidgets/MyDrawImgs/QStockKLine.py b/QUANTAXIS_Monitor_GUI/MyQtWidgets/MyDrawImgs/QStockKLine.py deleted file mode 100644 index 732afb77e..000000000 --- a/QUANTAXIS_Monitor_GUI/MyQtWidgets/MyDrawImgs/QStockKLine.py +++ /dev/null @@ -1,183 +0,0 @@ -from PyQt5.Qt import QLabel -from PyQt5.Qt import QDialog -from PyQt5.Qt import QMessageBox -from PyQt5.Qt import QHBoxLayout -from PyQt5.Qt import * -from PyQt5.QtGui import * -from PyQt5.QtCore import * - - -from typing import List - -import math -import numpy as np - - -from QUANTAXIS.QAUtil.QADate import * -from QUANTAXIS.QAUtil.QADate_trade import * - -from QUANTAXIS.QAFetch.QAQuery_Advance import * - - - -class CanvasKLines: - def __init__(self): - self.myCanvasKLine = QImage() - - mouseX = 0.0 - mouseY = 0.0 - - xInGrid = 0.0 - self.showDayInGauges = 100 - - - pass - - def setDrawImageSize(self, rect: QRect): - - self.myCanvasKLine = QImage(rect, QImage.Format_ARGB32) - self.myCanvasKLine.fill(QColor.fromRgb(0, 0, 0, 0)) - - self.parentHeight = self.myCanvasKLine.height() - self.parentWidth = self.myCanvasKLine.width() - - pass - - - def draw(self): - - try: - - - self.myCanvasKLine.fill(QColor.fromRgb(0, 0, 0, 0)) - - if self.oclhList is None: - return - - h = self.myCanvasKLine.height() - w = self.myCanvasKLine.width() - painter = QPainter(self.myCanvasKLine) - - - priceRange = self.highestPriceInScreen - self.lowestPriceInScreen - priceGapCount = priceRange *100 - - pricePerGapHeight = h / priceGapCount - - kLineDayWidth = w / self.showDayInGauges - - sizeOfLoadTradeDayList = len(self.tradeDayList) - - for iIndexKLine in range(len(self.oclhList)): - - if (sizeOfLoadTradeDayList - self.showDayInGauges) >= 0: - - - aKlineData = self.oclhList[self.showDayInGauges - iIndexKLine - 1] - - elif (sizeOfLoadTradeDayList - iIndexKLine) > 0: - - aKlineData = self.oclhList[sizeOfLoadTradeDayList - iIndexKLine - 1] - - - openprice = aKlineData[0] - closeprice = aKlineData[1] - lowprice = aKlineData[2] - highprice = aKlineData[3] - - # openPriceInScreen = (self.highestPriceInScreen - openprice) *100 *pricePerGapHeight - # closePriceInScreen = (self.highestPriceInScreen - closeprice) *100 *pricePerGapHeight - # - # lowPriceInScreen = (self.highestPriceInScreen- lp) *100 *pricePerGapHeight - # highpriceInScreen = (self.highestPriceInScreen - hp) *100 *pricePerGapHeight - # - - - # openPriceInScreen = (openprice - self.lowestPriceInScreen ) *100 *pricePerGapHeight - # closePriceInScreen = (closeprice - self.lowestPriceInScreen) *100 *pricePerGapHeight - # lowPriceInScreen = (lowprice - self.lowestPriceInScreen) *100 *pricePerGapHeight - # highpriceInScreen = (highprice - self.lowestPriceInScreen) *100 *pricePerGapHeight - - heightFromMinPriceOpen = (openprice - self.lowestPriceInScreen) * (100) * pricePerGapHeight - heihgtFromMaxPriceOpen = h - heightFromMinPriceOpen - openPrice_ScreenCoorY = 0 + heihgtFromMaxPriceOpen - - heightFromMinPriceClose = (closeprice - self.lowestPriceInScreen) * (100) * pricePerGapHeight - heihgtFromMaxPriceClose = h - heightFromMinPriceClose - closePrice_ScreenCoorY = 0 + heihgtFromMaxPriceClose - - heightFromMinPriceLow = (lowprice - self.lowestPriceInScreen) * (100) * pricePerGapHeight - heihgtFromMaxPriceLow = h - heightFromMinPriceLow - lowPrice_ScreenCoorY = 0 + heihgtFromMaxPriceLow - - heightFromMinPriceHigh = (highprice - self.lowestPriceInScreen) * (100) * pricePerGapHeight - heihgtFromMaxPriceHigh = h - heightFromMinPriceHigh - highPrice_ScreenCoorY = 0 + heihgtFromMaxPriceHigh - - #qp = QPoint(iIndexKLine * kLineDayWidth, openPriceInScreen) - #painter.drawPoint(qp) - kLineHeight = abs(closePrice_ScreenCoorY - openPrice_ScreenCoorY) - - qline = QLineF(iIndexKLine * kLineDayWidth + kLineDayWidth / 2, lowPrice_ScreenCoorY, \ - iIndexKLine * kLineDayWidth + kLineDayWidth / 2, highPrice_ScreenCoorY) - painter.drawLine(qline) - - if openprice > closeprice: - rectKLine = QRectF(iIndexKLine*kLineDayWidth, openPrice_ScreenCoorY, kLineDayWidth, kLineHeight ) - - painter.fillRect(rectKLine, QColor.fromRgb(0,200,0)) - - - else: - rectKLine = QRectF(iIndexKLine*kLineDayWidth, closePrice_ScreenCoorY, kLineDayWidth, kLineHeight) - - painter.fillRect(rectKLine, QColor.fromRgb(200,0,0)) - - - painter.drawRect(rectKLine) - - pass - except Exception as eee: - strError = eee.__str__() - print(strError) - - - pass - - def clearImage(self): - painter = QPainter(self.myCanvasKLine) - h = self.myCanvasKLine.height() - w = self.myCanvasKLine.width() - painter.fillRect(0, 0, w, h, QColor.fromRgb(0, 0, 0, 0)) - - oclhList = None - tradeDayList = None - - - # todo 直接使用 dataframe 来使用数据 - def setTradeDayListAndOCLH(self, tradeDateList: List[str], oclhList :np.ndarray, - highestPriceInScreen: float, lowestPriceInScreen : float, showDay : int): - - - #self.oclhList = oclhList[::-1] - self.oclhList = oclhList - self.tradeDayList = tradeDateList - self.showDayInGauges = showDay - - self.lowestPriceInScreen = lowestPriceInScreen - self.highestPriceInScreen = highestPriceInScreen - - def getMousePositionPrice(self,xInGrid: int): - - - if self.oclhList is not None and xInGrid < len(self.oclhList): - - openP = self.oclhList[xInGrid][0] - closeP = self.oclhList[xInGrid][1] - lowP = self.oclhList[xInGrid][2] - highP = self.oclhList[xInGrid][3] - - return [openP, closeP, lowP, highP] - else: - return None - pass diff --git a/QUANTAXIS_Monitor_GUI/MyQtWidgets/MyDrawImgs/QStockLeftPriceRuler.py b/QUANTAXIS_Monitor_GUI/MyQtWidgets/MyDrawImgs/QStockLeftPriceRuler.py deleted file mode 100644 index 0d434e354..000000000 --- a/QUANTAXIS_Monitor_GUI/MyQtWidgets/MyDrawImgs/QStockLeftPriceRuler.py +++ /dev/null @@ -1,104 +0,0 @@ -from PyQt5.Qt import QLabel -from PyQt5.Qt import QDialog -from PyQt5.Qt import QMessageBox -from PyQt5.Qt import QHBoxLayout -from PyQt5.Qt import * -from PyQt5.QtGui import * -from PyQt5.QtCore import * - - -from typing import List - -import math -import numpy as np - - -from QUANTAXIS.QAUtil.QADate import * -from QUANTAXIS.QAUtil.QADate_trade import * - -from QUANTAXIS.QAFetch.QAQuery_Advance import * - - -#from QUANTAXIS_Monitor_GUI.MyQtWidgets.QStockDateRuler import * - - -class CanvasLeftPriceRuler: - def __init__(self): - self.myCanvasPriceRuler = QImage() - - self.width = 35 - - self.minPrice = 8.0 - self.maxPrice = 88.0 - - self.parentHeight = 0 - self.parentWidth = 0 - - - self.defaultPriceGapCount = 50 - self.priceTextWidth = 30 - - pass - - def setPriceRange(self, maxP :float , minP :float): - self.maxPrice = maxP - self.minPrice = minP - - - def setDrawImageSize(self, rect: QRect): - - self.myCanvasPriceRuler = QImage(rect, QImage.Format_ARGB32) - self.myCanvasPriceRuler.fill(QColor.fromRgb(0, 0, 0, 0)) - - self.parentWidth = self.myCanvasPriceRuler.width() - self.parentHeight = self.myCanvasPriceRuler.height() - - # - # pass - - def clearImage(self): - painter = QPainter(self.myCanvasPriceRuler) - h = self.myCanvasPriceRuler.height() - w = self.myCanvasPriceRuler.width() - painter.fillRect(0, 0, w, h, QColor.fromRgb(0, 0, 0,0)) - - - def draw(self): - - try: - self.myCanvasPriceRuler.fill(QColor.fromRgb(0, 0, 0, 0)) - - - priceRangeGap = int(self.maxPrice - self.minPrice) - - heightGuage = (self.myCanvasPriceRuler.height() / self.defaultPriceGapCount) - - priceGap = priceRangeGap / self.defaultPriceGapCount - - painter = QPainter(self.myCanvasPriceRuler) - - if heightGuage > 0: - painter.save() - - for i in range(self.defaultPriceGapCount): - #painter.fillRect(0, 0, w, h, QColor.fromRgb(255, 255, 255)) - painter.drawRect(self.priceTextWidth, heightGuage*i, self.width, heightGuage ) - - - qp = QPoint(0, heightGuage*i+ heightGuage/2) - - painter.setFont(QFont('SansSerif', 10)) - - strPrice = "%0.2f"%(self.maxPrice - priceGap * i) - - painter.drawText(qp,strPrice) - - - painter.restore() - - - except Exception as eee: - strErro = eee.__str__() - print(strErro) - - pass \ No newline at end of file diff --git a/QUANTAXIS_Monitor_GUI/MyQtWidgets/MyDrawImgs/QStockMouseMove.py b/QUANTAXIS_Monitor_GUI/MyQtWidgets/MyDrawImgs/QStockMouseMove.py deleted file mode 100644 index 12910f7fa..000000000 --- a/QUANTAXIS_Monitor_GUI/MyQtWidgets/MyDrawImgs/QStockMouseMove.py +++ /dev/null @@ -1,67 +0,0 @@ -from PyQt5.QtGui import * -from PyQt5.QtCore import * - -from QUANTAXIS_Monitor_GUI.MyQtWidgets.MyDrawImgs.QStockDateRuler import CanvasBottomDateRuler -from QUANTAXIS_Monitor_GUI.MyQtWidgets.MyDrawImgs.QStockInfo import CanvasStockInfo - -class CanvasMouseCursor: - - mouseX = 0.0 - mouseY = 0.0 - - xInGrid = 0.0 - - def __init__(self): - self.myCanvasStockInfoMouseMove = QImage() - pass - - - def setDrawImageSize(self,rect:QRect): - - self.myCanvasStockInfoMouseMove = QImage(rect, QImage.Format_ARGB32) - self.myCanvasStockInfoMouseMove.fill(QColor.fromRgb(0, 0, 0, 0)) - - self.parentWidth = self.myCanvasStockInfoMouseMove.width() - self.parentHeight = self.myCanvasStockInfoMouseMove.height() - self.parentPosX = 0 - self.parentPoxY = 0 - - pass - - def draw(self, canvasDateRule : CanvasBottomDateRuler , canvasStockInfo : CanvasStockInfo): - - try: - h = self.myCanvasStockInfoMouseMove.height() - w = self.myCanvasStockInfoMouseMove.width() - - #变成透明, - self.myCanvasStockInfoMouseMove.fill(QColor.fromRgb(0, 0, 0, 0)) - - painter = QPainter(self.myCanvasStockInfoMouseMove) - - painter.fillRect(0, 0, w, h, QColor.fromRgb(0, 0, 0, 0)) - - painter.drawLine(self.xInGrid - self.parentPosX, 0, self.xInGrid - self.parentPosX, h) - painter.drawLine(0, self.mouseY - canvasStockInfo.height, w, self.mouseY - canvasStockInfo.height) - - - #canvasDateRule.setMousePositioin() - #canvasDateRule.drawSelectedDay(self.xInGrid - self.parentPosX) - - except Exception as eee: - strError = eee.__str__() - print(strError) - - - pass - - - - - - - def clearImage(self): - painter = QPainter(self.myCanvasStockInfoMouseMove) - h = self.myCanvasStockInfoMouseMove.height() - w = self.myCanvasStockInfoMouseMove.width() - painter.fillRect(0, 0, w, h, QColor.fromRgb(0, 0, 0, 0)) diff --git a/QUANTAXIS_Monitor_GUI/MyQtWidgets/MyDrawImgs/__init__.py b/QUANTAXIS_Monitor_GUI/MyQtWidgets/MyDrawImgs/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/QUANTAXIS_Monitor_GUI/MyQtWidgets/QStockPriceCanvas_old_no_use.py b/QUANTAXIS_Monitor_GUI/MyQtWidgets/QStockPriceCanvas_old_no_use.py deleted file mode 100644 index 07e21b0fe..000000000 --- a/QUANTAXIS_Monitor_GUI/MyQtWidgets/QStockPriceCanvas_old_no_use.py +++ /dev/null @@ -1,690 +0,0 @@ -from PyQt5.Qt import QLabel -from PyQt5.Qt import QDialog -from PyQt5.Qt import QMessageBox -from PyQt5.Qt import QHBoxLayout -from PyQt5.Qt import * -from PyQt5.QtGui import * -from PyQt5.QtCore import * - -import math -import numpy as np - -from QUANTAXIS.QAFetch.QAQuery_Advance import * - -from QUANTAXIS.QAUtil.QADate import * -from QUANTAXIS.QAUtil.QADate_trade import * - - -class QtStockPriceCanvas(QFrame): - def __init__(self, parent=None): - # parent not set to, none , 设置成parent 会死锁 - super(QtStockPriceCanvas, self).__init__(parent) - - self.pen = QPen() - self.brush = QBrush() - - self.myCanvasKLine = QImage() - self.myCanvasStockInfoMouseMove = QImage() - self.myCanvasStockInfo = QImage() - self.myCanvasPriceRuler = QImage() - self.myCanvasDateRuler = QImage() - - # def sizeHint(self): - # qsize = QSize() - # qsize.setHeight(800) - # qsize.setWidth(900) - # return qsize - - # draw somethings on the canvas - - ############################### - # 股票信息栏 # - ############################### - # 价格 # - # # - # # - # # - # # k线图 - # # - # # - # # - ################################ - - - - - LeftPriceWidth = 50 - BottomDateHeight = 20 - BottomCoordDatePt = [] - LeftPriceDatePt = [] - TopInfoHeight = 80 - - strCode = "" # 代码 - strFQ = "" # 复权 - strCyc = "" # 周期 - strCord = "" # 坐标类型 - #iZoomIn = 0 # 放到缩小 - - qaDataStuctDay = None - - oclh = None - - maxPriceInScreen = 0 - minPriceInScreen = 0 - - - tradeDays = None - - #默认加载的天数 - defaultLoadKLineDayCount = 300 - #显示的天数 - showKLineDayCount = 100 - - moveForward = 0 - strCurrentMouseDate = "" - - - - - - - def setCode(self, strCode): - self.strCode = strCode - - - def loadCodeData(self): - - try: - self.qaDataStuctDay = QA_fetch_stock_day_adv(self.strCode) - - - #QA_util_date_stamp() - #self.qaDataStuctDay.select_time(start=) - - - strToday=QA_util_today_str() - strTradeDayEnd = QA_util_get_real_date(strToday) - - - strTradeDayEnd = QA_util_get_last_day(strTradeDayEnd, self.moveForward) - - - strTradeDayStart = QA_util_get_last_day(strTradeDayEnd, self.defaultLoadKLineDayCount) # 获取近100天的数据 - - - self.qaDataStuctDay = self.qaDataStuctDay.select_time(strTradeDayStart, strTradeDayEnd) - self.qaDataStuctDay.to_qfq() - - # 找出最高价和最低价 - h = self.qaDataStuctDay.high - l = self.qaDataStuctDay.low - - #hl serial - posh = h.values.argmax() - posl = l.values.argmin() - - self.maxPriceInScreen = h[posh] - self.minPriceInScreen = l[posl] - - self.lowestPrice = l[posl] - self.highestPrice = h[posh] - - - self.maxPriceInScreen = float(math.ceil(self.maxPriceInScreen)) - self.minPriceInScreen = float(math.floor(self.minPriceInScreen)) - - ds = self.qaDataStuctDay.select_code(self.strCode) - self.oclh = np.array(ds.data.loc[:, ['open', 'close', 'low', 'high']]) - self.datesOfThisStockTrade = ds.datetime.to_series() - - self.tradeDays = [] - - dates_value = self.datesOfThisStockTrade.values - for i in range(len(dates_value)): - vdt64 = dates_value[i] - strTimeOfTradeDay = str(vdt64)[:10] - self.tradeDays.append(strTimeOfTradeDay) - - self.tradeDays.reverse() - self.oclh = self.oclh[::-1] - - self.oclh[0][0] - self.oclh[0][1] - self.oclh[0][2] - self.oclh[0][3] - - - - except Exception as ee: - strErro = ee.__str__() - print(strErro) - - def moveLeftChart(self): - - try: - if self.moveForward <= self.defaultLoadKLineDayCount - self.showKLineDayCount: - self.moveForward = self.moveForward + 1 - - self.loadCodeData() - self.drawCoordinate() - self.drawKLine() - self.drawStockInfo() - - - except Exception as ee: - strErro = ee.__str__() - print(strErro) - - pass - - def moveRightChart(self): - - - try: - if self.moveForward >= 0: - self.moveForward = self.moveForward - 1 - - self.loadCodeData() - self.drawCoordinate() - self.drawKLine() - self.drawStockInfo() - - - pass - except Exception as ee: - strErro = ee.__str__() - print(strErro) - - pass - - def zoomIn(self): - try: - if (self.showKLineDayCount-30) >= 100: - self.showKLineDayCount = self.showKLineDayCount - 30 - - self.loadCodeData() - self.drawCoordinate() - self.drawKLine() - self.drawStockInfo() - - pass - except Exception as ee: - strErro = ee.__str__() - print(strErro) - pass - - def zoomOut(self): - - try: - if (self.showKLineDayCount+30) <= self.defaultLoadKLineDayCount: - self.showKLineDayCount = self.showKLineDayCount + 30 - - self.loadCodeData() - self.drawCoordinate() - self.drawKLine() - self.drawStockInfo() - - - pass - except Exception as ee: - strErro = ee.__str__() - print(strErro) - - pass - - def clearAllImage(self): - - try: - widthOfCurrentDraw = self.width() - heightOfCurrentDraw = self.height() - - c = QColor.fromRgb(0, 0, 0, alpha=0) - self.myCanvasStockInfoMouseMove.fill(c) - self.myCanvasStockInfo.fill(c) - self.myCanvasPriceRuler.fill(c) - self.myCanvasKLine.fill(c) - self.myCanvasDateRuler.fill(c) - - except Exception as eee: - strErro = eee.__str__() - print(strErro) - pass - - ################################################################################################ - - def drawCoordinate(self): - - try: - - #alpha = 0 透明 - #全部清除 - self.myCanvasPriceRuler.fill(QColor.fromRgb(0,0,0,0)) - painterPriceRuler = QPainter(self.myCanvasPriceRuler) - painterPriceRuler.fillRect(0,0,self.width(),self.height(), QColor.fromRgb(0,0,0,0)) - - ############################################################################################################ - - widthOfCurrentDraw = self.LeftPriceWidth - heightOfCurrentDraw = self.height() - self.TopInfoHeight -self.BottomDateHeight - - - painterPriceRuler.fillRect(0, self.TopInfoHeight , widthOfCurrentDraw, heightOfCurrentDraw , QColor.fromRgb(0x00FFFF)) - - - if self.maxPriceInScreen == 0 and self.minPriceInScreen == 0: - self.maxPriceInScreen = 88 - self.minPriceInScreen = 8 - - priceRange = (self.maxPriceInScreen - self.minPriceInScreen) - - - priceGapCount = 20 - - priceSegmentHeight = heightOfCurrentDraw / priceGapCount - # - for i in range(priceGapCount): - priceScreenCoorY = self.height() - self.BottomDateHeight - (priceSegmentHeight * i ) - # - # if i == 0: - # #priceScreenCoorY + - # - # qp = QPoint(0, priceScreenCoorY) - # priceShow = '%0.2f' % (self.lowestPrice + priceRange / 10 * i) - # painterPriceRuler.drawText(qp, priceShow) - # - # qp2 = QPoint(self.LeftPriceWidth, priceScreenCoorY) - # painterPriceRuler.drawLine(qp, qp2) - - #if i == 50: - #priceScreenCoorY = priceScreenCoorY + 10 - - qp = QPoint(0, priceScreenCoorY+5) - priceShow = '%0.2f' % (self.minPriceInScreen + priceRange / priceGapCount * i) - painterPriceRuler.drawText(qp, priceShow) - - qp = QPoint(self.LeftPriceWidth-10, priceScreenCoorY) - qp2 = QPoint(self.LeftPriceWidth, priceScreenCoorY) - painterPriceRuler.drawLine(qp, qp2) - - - painterPriceRuler.save() - - pen= QPen(); - pen.setStyle(Qt.DashDotDotLine) - pen.setBrush(QBrush(Qt.blue)); # 设置笔刷, - - - painterPriceRuler.setPen(pen) - - qp3 = QPoint(self.width(), priceScreenCoorY) - painterPriceRuler.drawLine(qp2, qp3) - - painterPriceRuler.restore() - - centCount = priceRange * 10 - - centCountPart = math.modf(centCount) - iCount = int(centCountPart[1]) - - iRuleGapSize = heightOfCurrentDraw / iCount - - # for i in range(iCount): - # - # rulerScreenCoorY = self.height() - self.BottomDateHeight - (iRuleGapSize * i) - # - # aRect = QRectF(self.LeftPriceWidth-5, rulerScreenCoorY, self.LeftPriceWidth, rulerScreenCoorY + iRuleGapSize) - # painterPriceRuler.drawRect(aRect) - - pass - - ############################################################################################################ - - # alpha = 0 透明 - # 全部清除 - self.myCanvasDateRuler.fill(QColor.fromRgb(0, 0, 0, 0)) - painterDateRuler = QPainter(self.myCanvasDateRuler) - painterDateRuler.fillRect(0, 0, self.width(), self.height(), QColor.fromRgb(0, 0, 0, 0)) - - widthOfCurrentDraw = self.width() - self.LeftPriceWidth - heightOfCurrentDraw = self.height() - - - if self.tradeDays is None: - strToday = QA_util_today_str() - strTradeDayEnd = QA_util_get_real_date(strToday) - - - painterDateRuler.fillRect(self.LeftPriceWidth, heightOfCurrentDraw- self.BottomDateHeight, widthOfCurrentDraw, heightOfCurrentDraw, QColor.fromRgb(120,221,232,255)) - - dateGapCount = ((widthOfCurrentDraw)/ self.showKLineDayCount) - - self.BottomCoordDatePt = [] - for i in range(self.showKLineDayCount): # 计算坐标的时候需要 - - # painter.drawLine(self.LeftPriceWidth+dateGapCount*i, heightOfCurrentDraw - self.BottomDateHeight, self.LeftPriceWidth+dateGapCount*i, heightOfCurrentDraw-10) - if self.tradeDays is not None and i >= len(self.tradeDays): - continue - - - painterDateRuler.drawRect(self.LeftPriceWidth+dateGapCount*i, heightOfCurrentDraw - self.BottomDateHeight, dateGapCount, 5) - self.BottomCoordDatePt.append(self.LeftPriceWidth+dateGapCount*i) - - if (i % 20 == 0) or i ==0 or i == (self.showKLineDayCount-1): - - painterDateRuler.fillRect(self.LeftPriceWidth+dateGapCount*i, heightOfCurrentDraw - self.BottomDateHeight, dateGapCount, 5, QColor.fromRgb(0,255,0)) - - if self.tradeDays is None: - strDateOnRuler = QA_util_get_last_day(strTradeDayEnd, (self.showKLineDayCount-1) - i ) # 获取近100天的数据 - strDateOnRuler = QA_util_get_real_date(strDateOnRuler) - else: - if ((self.showKLineDayCount-1)-i) < len(self.tradeDays): - strDateOnRuler = self.tradeDays[(self.showKLineDayCount-1)-i] - - print(strDateOnRuler) - - if i == 0: - qp1 = QPoint(self.LeftPriceWidth+dateGapCount*i, heightOfCurrentDraw) - elif i == (self.showKLineDayCount-1): - qp1 = QPoint(self.LeftPriceWidth+dateGapCount*i-70, heightOfCurrentDraw) - else: - qp1 = QPoint(self.LeftPriceWidth+dateGapCount*i-35, heightOfCurrentDraw) - - painterDateRuler.drawText(qp1,"{}".format(strDateOnRuler)) - - #添加最后一个日期坐标轴 - self.BottomCoordDatePt.append(self.LeftPriceWidth + dateGapCount * self.showKLineDayCount) - - self.update() - - except Exception as eee: - strErro = eee.__str__() - print(strErro) - - - def drawStockInfo(self): - - try: - - widthOfCurrentDraw = self.width() - heightOfCurrentDraw = self.height() - - # 全部清除,变成透明 - self.myCanvasStockInfo.fill(QColor.fromRgb(0, 0, 0, alpha=0)) - painterMouse = QPainter(self.myCanvasStockInfo); - - rectClear = QRect(0, 0, self.width(), self.height()) - painterMouse.fillRect(rectClear, QColor.fromRgb(0, 0, 0, alpha=0)) - - painterMouse.fillRect(0,0, widthOfCurrentDraw, self.TopInfoHeight, QColor.fromRgb(111,111,222,alpha=255)) - - - except Exception as eeee: - strErro = eeee.__str__() - print(strErro) - - - - - def drawKLine(self): - - try: - - # alpha = 0 透明 - # 全部清除 - self.myCanvasKLine.fill(QColor.fromRgb(0, 0, 0, 0)) - painterKLine = QPainter(self.myCanvasKLine) - painterKLine.fillRect(0, 0, self.width(), self.height(), QColor.fromRgb(0, 0, 0, 0)) - - ############################################################################################################ - - # painter = QPainter(self.myCanvas) - # self.myCanvas.fill(QColor.fromRgb(255,255,255)) - # - - widthOfCurrentDraw = self.width() - self.LeftPriceWidth - heightOfCurrentDraw = self.height() - self.TopInfoHeight - self.BottomDateHeight - - # # ruleGapY = heightOfCurrentDraw / 10 - ruleGapX = widthOfCurrentDraw / (self.showKLineDayCount) - - if self.maxPriceInScreen != 0 and self.minPriceInScreen != 0: - if self.oclh is not None: - - priceRange = (self.maxPriceInScreen - self.minPriceInScreen) * (self.showKLineDayCount) - pixelCountInUnit = (heightOfCurrentDraw / priceRange) - - #for i in range(len(self.ohlc)): - - #if len(self.oclh) < self.showKLineDayCount: - #break; - - for i in range((self.showKLineDayCount)): - #print(self.oclh[i]) - - - if ((self.showKLineDayCount-1)-i) >= len(self.oclh): - # openprice =0 - # closeprice=0 - # lowprice =0 - # highprice=0 - continue - else: - - openprice = self.oclh[(self.showKLineDayCount-1)-i][0] - closeprice = self.oclh[(self.showKLineDayCount-1)-i][1] - lowprice = self.oclh[(self.showKLineDayCount-1)-i][2] - highprice = self.oclh[(self.showKLineDayCount-1)-i][3] - - if self.maxPriceInScreen != 0 and self.minPriceInScreen != 0: - - heightFromMinPriceOpen = (openprice - self.minPriceInScreen) * (self.showKLineDayCount) * pixelCountInUnit - heihgtFromMaxPriceOpen = heightOfCurrentDraw - heightFromMinPriceOpen - openPrice_ScreenCoorY = self.TopInfoHeight + heihgtFromMaxPriceOpen - - heightFromMinPriceClose = (closeprice - self.minPriceInScreen) * (self.showKLineDayCount) * pixelCountInUnit - heihgtFromMaxPriceClose = heightOfCurrentDraw - heightFromMinPriceClose - closePrice_ScreenCoorY = self.TopInfoHeight + heihgtFromMaxPriceClose - - heightFromMinPriceLow = (lowprice - self.minPriceInScreen) * (self.showKLineDayCount) * pixelCountInUnit - heihgtFromMaxPriceLow = heightOfCurrentDraw - heightFromMinPriceLow - lowPrice_ScreenCoorY = self.TopInfoHeight + heihgtFromMaxPriceLow - - heightFromMinPriceHigh = (highprice - self.minPriceInScreen) * (self.showKLineDayCount) * pixelCountInUnit - heihgtFromMaxPriceHigh = heightOfCurrentDraw - heightFromMinPriceHigh - highPrice_ScreenCoorY = self.TopInfoHeight + heihgtFromMaxPriceHigh - - - #painterKLine.drawLine(self.LeftPriceWidth+i*ruleGapX, openPrice_ScreenCoorY,self.LeftPriceWidth+i*ruleGapX+ruleGapX, openPrice_ScreenCoorY ) - rectKLineEntityHigh = abs(closePrice_ScreenCoorY - openPrice_ScreenCoorY) - - - painterKLine.drawLine(self.LeftPriceWidth + i * ruleGapX + ruleGapX / 2, - highPrice_ScreenCoorY, - self.LeftPriceWidth + i * ruleGapX + ruleGapX / 2, - lowPrice_ScreenCoorY) - - if openprice >= closeprice: - rectKLineEntiry = QRectF(self.LeftPriceWidth+i*ruleGapX,openPrice_ScreenCoorY,ruleGapX, rectKLineEntityHigh) - painterKLine.fillRect(rectKLineEntiry,QColor.fromRgb(0,255,0)) - painterKLine.drawRect(rectKLineEntiry) - - - else: - rectKLineEntiry = QRectF(self.LeftPriceWidth+i*ruleGapX,closePrice_ScreenCoorY,ruleGapX, rectKLineEntityHigh) - painterKLine.fillRect(rectKLineEntiry,QColor.fromRgb(255,0,0)) - painterKLine.drawRect(rectKLineEntiry) - - - - - self.update() - except Exception as eee: - strErro = eee.__str__() - print(strErro) - pass - - ################################################################################################################ - def mouseMoveEvent(self, a0: QMouseEvent): - - try: - widthOfCurrentDraw = self.width() - heightOfCurrentDraw = self.height() - - pos = a0.pos() - - #全部清除,变成透明 - self.myCanvasStockInfoMouseMove.fill(QColor.fromRgb(0, 0, 0, alpha=0)) - painterMouse = QPainter(self.myCanvasStockInfoMouseMove); - - rectClear = QRect(0,0,self.width(), self.height()) - painterMouse.fillRect(rectClear, QColor.fromRgb(0,0,0,alpha=0)) - - - strToday = QA_util_today_str() - strTradeDayEnd = QA_util_get_real_date(strToday) - - if self.maxPriceInScreen != 0 and self.minPriceInScreen != 0: - - priceRange = (self.maxPriceInScreen - self.minPriceInScreen) * (self.showKLineDayCount) - priceCountInUnit = ( priceRange / heightOfCurrentDraw) - priceLogicalCoorY = (priceCountInUnit * (heightOfCurrentDraw -pos.y())) /(self.showKLineDayCount) + self.minPriceInScreen - #strDraw = '屏幕坐标%0.2f,%0.2f ,价格区间%f , 单位价格占用屏幕像素 %f 价格%0.2f ' % (pos.x(), pos.y(), priceRange, priceLogicalCoorY, priceLogicalCoorY) - else: - strDraw = '%0.2f,%0.2f' % (pos.x(),pos.y()) - - qp = QPoint(self.LeftPriceWidth, 10) - painterMouse.drawText(qp,strDraw) - - ''' - ' ' ' ' ' ' - ''' - #fix here 使用股票价格的日期数据 - mouseXPt = pos.x() - if len(self.BottomCoordDatePt) >0: - for indexOfDate in range(len(self.BottomCoordDatePt)): - - if indexOfDate < len(self.BottomCoordDatePt) and indexOfDate+1 < len(self.BottomCoordDatePt): - - if indexOfDate= self.BottomCoordDatePt[indexOfDate] and mouseXPt < self.BottomCoordDatePt[indexOfDate+1]: - - - if self.tradeDays is None: - strDateOnRuler = QA_util_get_last_day(strTradeDayEnd, (self.showKLineDayCount-1)-indexOfDate) # 获取近100天的数据 - self.strCurrentMouseDate = strDateOnRuler - else: - self.strCurrentMouseDate = self.tradeDays[(self.showKLineDayCount-1)-indexOfDate] - - qp = QPoint(self.LeftPriceWidth + (self.showKLineDayCount), 10) - strDraw = "日期:%s" % (self.strCurrentMouseDate) - painterMouse.drawText(qp, strDraw) - - qp = QPoint(self.LeftPriceWidth + 300, 10) - - #if len(self.oclh) < - if ((self.showKLineDayCount-1)-indexOfDate) >= len(self.oclh): - strDrawPrice ="" - else: - - strDrawPrice = "开盘: {} 收盘: {} 最低:{} 最高:{}".format( - self.oclh[(self.showKLineDayCount-1)-indexOfDate][0], - self.oclh[(self.showKLineDayCount-1)-indexOfDate][1], - self.oclh[(self.showKLineDayCount-1)-indexOfDate][2], - self.oclh[(self.showKLineDayCount-1)-indexOfDate][3]) - painterMouse.drawText(qp, strDrawPrice) - - #dateGapCountWidth = ((widthOfCurrentDraw)/100) - - dateGapCountInScreen = (self.BottomCoordDatePt[indexOfDate] + self.BottomCoordDatePt[indexOfDate+1])/2 - #纵坐标 - painterMouse.drawLine(dateGapCountInScreen, self.TopInfoHeight, dateGapCountInScreen, heightOfCurrentDraw) - #横坐标 - painterMouse.drawLine(0, pos.y(), widthOfCurrentDraw, pos.y()) - - break - - self.update() - pass - except Exception as eeee: - strErro = eeee.__str__() - print(strErro) - - def keyPressEvent(self, a0: QKeyEvent): - - if Qt.Key_Left == a0.key(): - print("left key") - pass - - if Qt.Key_Right == a0.key(): - print("right key") - - pass - - pass - - def resizeEvent(self, a0: QResizeEvent): - if self.width() > self.myCanvasKLine.width() or self.height() > self.myCanvasKLine.height() or \ - self.width() > self.myCanvasPriceRuler.width() or self.height() > self.myCanvasPriceRuler.height() or \ - self.width() > self.myCanvasStockInfoMouseMove.width() or self.height() > self.myCanvasStockInfoMouseMove.height() or \ - self.width() > self.myCanvasStockInfo.width() or self.height() > self.myCanvasStockInfo.height() or \ - self.width() > self.myCanvasDateRuler.width() or self.height() > self.myCanvasDateRuler.height() : - - newSizea = a0.size() - newWidth = newSizea.width() - newHeight = newSizea.height() - - - - self.myCanvasPriceRuler = QImage(QSize(newWidth, newHeight), QImage.Format_ARGB32) - # QPainter painter( & newImage); - painter = QPainter(self.myCanvasPriceRuler) - painter.drawImage(QPoint(0, 0), self.myCanvasPriceRuler); - - self.myCanvasDateRuler = QImage(QSize(newWidth, newHeight), QImage.Format_ARGB32) - # QPainter painter( & newImage); - painter = QPainter(self.myCanvasDateRuler) - painter.drawImage(QPoint(0, 0), self.myCanvasDateRuler); - - self.myCanvasKLine = QImage(QSize(newWidth, newHeight) , QImage.Format_ARGB32) - # QPainter painter( & newImage); - painter = QPainter(self.myCanvasKLine) - painter.drawImage(QPoint(0, 0), self.myCanvasKLine); - - self.myCanvasStockInfoMouseMove = QImage(QSize(newWidth, newHeight), QImage.Format_ARGB32) - # QPainter painter( & newImage); - painter = QPainter(self.myCanvasStockInfoMouseMove) - painter.drawImage(QPoint(0, 0), self.myCanvasStockInfoMouseMove); - - self.myCanvasStockInfo = QImage(QSize(newWidth, newHeight), QImage.Format_ARGB32) - # QPainter painter( & newImage); - painter = QPainter(self.myCanvasStockInfo) - painter.drawImage(QPoint(0, 0), self.myCanvasStockInfo); - - def paintEvent(self,qPaintEvent): - - try: - painter = QPainter(self) - #dirtyRect =QRect() - dirtyRect = qPaintEvent.rect(); - - painter.fillRect(dirtyRect, QColor.fromRgb(255,255,255)) - - painter.drawImage(dirtyRect, self.myCanvasPriceRuler, dirtyRect); - painter.drawImage(dirtyRect, self.myCanvasDateRuler, dirtyRect) - - painter.drawImage(dirtyRect, self.myCanvasKLine, dirtyRect); - painter.drawImage(dirtyRect, self.myCanvasStockInfo, dirtyRect); - - painter.drawImage(dirtyRect, self.myCanvasKLine, dirtyRect); - painter.drawImage(dirtyRect, self.myCanvasStockInfoMouseMove, dirtyRect); - - except Exception as eee: - strErro = eee.__str__() - print(strErro) - pass - - - - - - - diff --git a/QUANTAXIS_Monitor_GUI/MyQtWidgets/QStockPriceVolumeCanvas.py b/QUANTAXIS_Monitor_GUI/MyQtWidgets/QStockPriceVolumeCanvas.py deleted file mode 100644 index e541f33ee..000000000 --- a/QUANTAXIS_Monitor_GUI/MyQtWidgets/QStockPriceVolumeCanvas.py +++ /dev/null @@ -1,394 +0,0 @@ -from QUANTAXIS_Monitor_GUI.MyQtWidgets.MyDrawImgs.QStockDateRuler import * -from QUANTAXIS_Monitor_GUI.MyQtWidgets.MyDrawImgs.QStockLeftPriceRuler import * -from QUANTAXIS_Monitor_GUI.MyQtWidgets.MyDrawImgs.QStockMouseMove import * -from QUANTAXIS_Monitor_GUI.MyQtWidgets.MyDrawImgs.QStockKLine import * -from QUANTAXIS_Monitor_GUI.MyQtWidgets.MyDrawImgs.QStockInfo import * -from QUANTAXIS_Monitor_GUI.MyQtWidgets.MyDrawImgs.QStockGMMA import * -from QUANTAXIS.QAIndicator import QA_indicator_MA - - -class MidVolume: - def __init__(self): - self.myCanvasMidVolume = QImage() - pass - - def setDrawImageSize(self, rect: QRect): - pass - - - -class QtStockPriceVolumeFrame(QFrame): - def __init__(self, parent=None): - # parent not set to, none , 设置成parent 会死锁 - super(QtStockPriceVolumeFrame, self).__init__(parent) - - self.pen = QPen() - self.brush = QBrush() - - #self.canvasLeftPriceRuler = LeftPriceRuler() - self.canvasBottomDateRuler = CanvasBottomDateRuler() - self.canvasLeftPriceRuler = CanvasLeftPriceRuler() - self.canvasMouseMove = CanvasMouseCursor() - self.canvasKLine = CanvasKLines() - self.canvasStockInfo = CanvasStockInfo() - self.canvasGMMA = CanvasGMMA() - - - self.strCode = "002433" - self.moveForward = 0 - - self.MaxDayLoad = 1000 - self.MinDayLoad = 100 - - self.currentLoadKLineDayCount = self.MinDayLoad - - - def resizeEvent(self, a0: QResizeEvent): - try: - - newSizea = a0.size() - - canvasWidth = newSizea.width() - canvasHeight = newSizea.height() - - #if self.width() > self.bottomDateRuler.myCanvasDateRuler.width() or \ - # self.height() > self.bottomDateRuler.myCanvasDateRuler.height(): - - stockInfoSize = QSize() - stockInfoSize.setWidth(canvasWidth) - stockInfoSize.setHeight(self.canvasStockInfo.height) - self.canvasStockInfo.setDrawImageSize(stockInfoSize) - - rulerSize = QSize() - rulerSize.setWidth(canvasWidth - self.canvasLeftPriceRuler.width) - rulerSize.setHeight(self.canvasBottomDateRuler.height) - self.canvasBottomDateRuler.setDrawImageSize(rulerSize) - - - rulePriceSize = QSize() - rulePriceSize.setWidth(self.canvasLeftPriceRuler.width) - rulePriceSize.setHeight(canvasHeight - self.canvasBottomDateRuler.height - self.canvasStockInfo.height) - self.canvasLeftPriceRuler.setDrawImageSize(rulePriceSize) - - - mouseCrossMoveSize = QSize() - mouseCrossMoveSize.setWidth(canvasWidth - self.canvasLeftPriceRuler.width) - mouseCrossMoveSize.setHeight(canvasHeight - self.canvasBottomDateRuler.height - self.canvasStockInfo.height) - self.canvasMouseMove.setDrawImageSize(mouseCrossMoveSize) - self.canvasMouseMove.parentPosX = self.canvasLeftPriceRuler.width - - - klineDrawSize = QSize() - klineDrawSize.setWidth(canvasWidth - self.canvasLeftPriceRuler.width) - klineDrawSize.setHeight(canvasHeight - self.canvasBottomDateRuler.height - self.canvasStockInfo.height) - self.canvasKLine.setDrawImageSize(klineDrawSize) - - kGmmaSize = QSize() - kGmmaSize.setWidth(canvasWidth - self.canvasLeftPriceRuler.width) - kGmmaSize.setHeight(canvasHeight - self.canvasBottomDateRuler.height - self.canvasStockInfo.height) - self.canvasGMMA.setDrawImageSize(kGmmaSize) - - #todo 画成交量 - #self.canvasKLine.parentPosX = self.canvasLeftPriceRuler.width - # mouseMove - - #rulerRect = (0,newHeightOfBottomDateRuler-20,newWidthOfBottomDateRuler, 20) - - #painter = QPainter(self.bottomDateRuler.myCanvasDateRuler) - #painter.drawImage(QPoint(200, 200), self.bottomDateRuler.myCanvasDateRuler); - - # self.myCanvasPriceRuler = QImage(QSize(newWidth, newHeight), QImage.Format_ARGB32) - # # QPainter painter( & newImage); - # painter = QPainter(self.myCanvasPriceRuler) - # painter.drawImage(QPoint(0, 0), self.myCanvasPriceRuler); - # - # - # self.myCanvasKLine = QImage(QSize(newWidth, newHeight) , QImage.Format_ARGB32) - # # QPainter painter( & newImage); - # painter = QPainter(self.myCanvasKLine) - # painter.drawImage(QPoint(0, 0), self.myCanvasKLine); - # - # self.myCanvasStockInfoMouseMove = QImage(QSize(newWidth, newHeight), QImage.Format_ARGB32) - # # QPainter painter( & newImage); - # painter = QPainter(self.myCanvasStockInfoMouseMove) - # painter.drawImage(QPoint(0, 0), self.myCanvasStockInfoMouseMove); - # - # self.myCanvasStockInfo = QImage(QSize(newWidth, newHeight), QImage.Format_ARGB32) - # # QPainter painter( & newImage); - # painter = QPainter(self.myCanvasStockInfo) - # painter.drawImage(QPoint(0, 0), self.myCanvasStockInfo); - - - pass - except Exception as eee: - strError = eee.__str__() - print(strError) - - def paintEvent(self, qPaintEvent: QPaintEvent): - try: - painter = QPainter(self) - #dirtyRect =QRect() - dirtyRect = qPaintEvent.rect(); - - painter.fillRect(dirtyRect, QColor.fromRgb(255,255,255)) - - #painter.drawImage(dirtyRect, self.myCanvasPriceRuler, dirtyRect); - #painter.drawImage(dirtyRect, self.bottomDateRuler.myCanvasDateRuler, dirtyRect) - - #painter = QPainter(self.bottomDateRuler.myCanvasDateRuler) - - w = self.width() - h = self.height() - - #股票信息 - painter.drawImage(QPoint(0, 0), self.canvasStockInfo.myCanvasStockInfo) - - - #日期坐标尺 - bottomDataRuleY = h - self.canvasBottomDateRuler.height - bottomDateRuleX = self.canvasLeftPriceRuler.width - painter.drawImage(QPoint(bottomDateRuleX, bottomDataRuleY), self.canvasBottomDateRuler.myCanvasDateRuler); - - - #价格坐标尺 - priceRuleYPos = self.canvasStockInfo.height - painter.drawImage(QPoint(0,priceRuleYPos), self.canvasLeftPriceRuler.myCanvasPriceRuler) - - #鼠标移动 - painter.drawImage(QPoint(self.canvasLeftPriceRuler.width, priceRuleYPos), self.canvasMouseMove.myCanvasStockInfoMouseMove) - - # k线 - painter.drawImage(QPoint(self.canvasLeftPriceRuler.width, priceRuleYPos), self.canvasKLine.myCanvasKLine) - - #Gmma 均线 - painter.drawImage(QPoint(self.canvasLeftPriceRuler.width, priceRuleYPos), self.canvasGMMA.myCanvasGMMA) - - - #鼠标十字光标 - - #painter.drawImage(dirtyRect, self.myCanvasKLine, dirtyRect); - #painter.drawImage(dirtyRect, self.myCanvasStockInfo, dirtyRect); - - #painter.drawImage(dirtyRect, self.myCanvasKLine, dirtyRect); - #painter.drawImage(dirtyRect, self.myCanvasStockInfoMouseMove, dirtyRect); - - except Exception as eee: - strErro = eee.__str__() - print(strErro) - pass - - - def mouseMoveEvent(self, a0: QMouseEvent): - - try: - strDraw = '%0.2f,%0.2f' % (a0.x(), a0.y()) - - pos = a0.pos() - print(pos) - - self.canvasMouseMove.mouseX = pos.x() - self.canvasMouseMove.mouseY = pos.y() - - self.canvasBottomDateRuler.mouseX = pos.x() - xInGrid = self.canvasBottomDateRuler.getMoseGapPosX( pos.x() ) - self.canvasMouseMove.xInGrid = xInGrid - - strDate = self.canvasBottomDateRuler.getMouseMouseDateStr(pos.x() - self.canvasLeftPriceRuler.width) - - - self.canvasBottomDateRuler.draw() - self.canvasLeftPriceRuler.draw() - self.canvasMouseMove.draw(self.canvasBottomDateRuler, self.canvasStockInfo) - - - oclhCurrentMouseMove = self.canvasKLine.getMousePositionPrice(self.canvasBottomDateRuler.getMouseGridIndex(pos.x())) - - #strDate = self.canvasBottomDateRuler.getMouseMouseDateStr(pos.x()) - #更新价格 - self.canvasStockInfo.setMouseMoveDate(strDate) - self.canvasStockInfo.setMouseMovePrice(oclhCurrentMouseMove) - - self.canvasStockInfo.setMousePositionInfo(pos.x() - self.canvasLeftPriceRuler.width ,pos.y() - self.canvasStockInfo.height ) - - self.canvasStockInfo.draw() - - self.update() - - except Exception as eee: - strErro = eee.__str__() - print(strErro) - - ######################################################################################### - - def clearAllImage(self): - try: - - self.canvasBottomDateRuler.clearImage() - self.canvasLeftPriceRuler.clearImage() - self.canvasMouseMove.clearImage() - self.canvasKLine.clearImage() - - self.update() - except Exception as eee: - strErro = eee.__str__() - print(strErro) - - pass - - def drawCoordinate(self): - - self.canvasBottomDateRuler.draw() - self.canvasLeftPriceRuler.draw() - self.canvasMouseMove.draw(self.canvasBottomDateRuler, self.canvasStockInfo) - - - - pass - - def drawKLine(self): - self.canvasKLine.draw() - self.canvasGMMA.draw() - pass - - def moveLeftChart(self): - pass - - def moveRightChart(self): - pass - - def zoomIn(self): - - if self.currentLoadKLineDayCount - 50 >= self.MinDayLoad: - self.currentLoadKLineDayCount = self.currentLoadKLineDayCount - 50 - pass - - def zoomOut(self): - - if self.currentLoadKLineDayCount + 50 <= self.MaxDayLoad: - self.currentLoadKLineDayCount = self.currentLoadKLineDayCount + 50 - pass - - def setCode(self, txtInputedCode: str, txtName: str): - - self.strCode = txtInputedCode - self.strName = txtName - self.canvasStockInfo.setCodeAndName(self.strName,self.strCode) - - pass - - - - def loadCodeData(self): - - - try: - # - #QA_util_date_stamp() - #self.qaDataStuctDay.select_time(start=) - - - strToday=QA_util_today_str() - strTradeDayEnd = QA_util_get_real_date(strToday) - - - strTradeDayEnd = QA_util_get_last_day(strTradeDayEnd, self.moveForward) - strTradeDayStart = QA_util_get_last_day(strTradeDayEnd, self.currentLoadKLineDayCount) # 获取近100天的数据 - - qaDataStuctDay = QA_fetch_stock_day_adv(self.strCode) - qaDataStuctDay = qaDataStuctDay.select_time(strTradeDayStart, strTradeDayEnd) - qaDataStuctDay.to_qfq() - - # 找出最高价和最低价 - h = qaDataStuctDay.high - l = qaDataStuctDay.low - - #hl serial - posh = h.values.argmax() - posl = l.values.argmin() - - - lowestPrice = l[posl] - highestPrice = h[posh] - - maxPriceInScreen = float(math.ceil(highestPrice)) - minPriceInScreen = float(math.floor(lowestPrice)) - - tradeDays = [] - - - ds = qaDataStuctDay.select_code(self.strCode) - oclh = np.array(ds.data.loc[:, ['open', 'close', 'low', 'high']]) - datesOfThisStockTrade = ds.datetime.to_series() - - - dates_value = datesOfThisStockTrade.values - for i in range(len(dates_value)): - vdt64 = dates_value[i] - strTimeOfTradeDay = str(vdt64)[:10] - tradeDays.append(strTimeOfTradeDay) - - tradeDays.reverse() - oclh = oclh[::-1] - - assert (len(tradeDays) == len(oclh)) - - self.canvasLeftPriceRuler.setPriceRange(maxPriceInScreen,minPriceInScreen) - self.canvasBottomDateRuler.setTradeDayList(tradeDays, self.currentLoadKLineDayCount) - - self.canvasKLine.setTradeDayListAndOCLH(tradeDays, oclh, maxPriceInScreen, minPriceInScreen, \ - self.currentLoadKLineDayCount) - - - - ###############################################################################################3 - # self.df_from_Tdx = QA_fetch_stock_day( - # '300439', self.time_to_Market_300439, self.time_to_day, 'pd') - # # print(self.df_from_Tdx) - # - # self.ma05 = QA_indicator_MA(self.df_from_Tdx, 5) - - strTradeDayEnd = QA_util_get_last_day(strTradeDayEnd, self.moveForward) - strTradeDayStart = QA_util_get_last_day(strTradeDayEnd, self.currentLoadKLineDayCount + 60) # 均线系统需要提前获取 - - qaDataStuctDayForMa = QA_fetch_stock_day_adv(self.strCode) - qaDataStuctDayForMa = qaDataStuctDayForMa.select_time(strTradeDayStart, strTradeDayEnd) - qaDataStuctDayForMa.to_qfq() - - ma03 = QA_indicator_MA(qaDataStuctDayForMa, 3) - ma05 = QA_indicator_MA(qaDataStuctDayForMa, 5) - ma08 = QA_indicator_MA(qaDataStuctDayForMa, 8) - ma10 = QA_indicator_MA(qaDataStuctDayForMa, 10) - ma12 = QA_indicator_MA(qaDataStuctDayForMa, 12) - - #30、35、40、45、50 和60 - ma30 = QA_indicator_MA(qaDataStuctDayForMa, 30) - ma35 = QA_indicator_MA(qaDataStuctDayForMa, 35) - ma40 = QA_indicator_MA(qaDataStuctDayForMa, 40) - ma45 = QA_indicator_MA(qaDataStuctDayForMa, 45) - ma50 = QA_indicator_MA(qaDataStuctDayForMa, 50) - ma60 = QA_indicator_MA(qaDataStuctDayForMa, 60) - - - #self.drawCoordinate() - self.canvasGMMA.setPriceRange(maxPriceInScreen,minPriceInScreen) - self.canvasGMMA.setTradeDays(tradeDays) - - self.canvasGMMA.set05MA(ma05, self.currentLoadKLineDayCount) - self.canvasGMMA.set03MA(ma03, self.currentLoadKLineDayCount) - self.canvasGMMA.set08MA(ma08, self.currentLoadKLineDayCount) - self.canvasGMMA.set10MA(ma10, self.currentLoadKLineDayCount) - self.canvasGMMA.set12MA(ma12, self.currentLoadKLineDayCount) - # - self.canvasGMMA.set30MA(ma30, self.currentLoadKLineDayCount) - self.canvasGMMA.set35MA(ma35, self.currentLoadKLineDayCount) - self.canvasGMMA.set40MA(ma40, self.currentLoadKLineDayCount) - self.canvasGMMA.set45MA(ma45, self.currentLoadKLineDayCount) - self.canvasGMMA.set50MA(ma50, self.currentLoadKLineDayCount) - self.canvasGMMA.set60MA(ma60, self.currentLoadKLineDayCount) - - - except Exception as ee: - strErro = ee.__str__() - print(strErro) - - pass \ No newline at end of file diff --git a/QUANTAXIS_Monitor_GUI/MyQtWidgets/__init__.py b/QUANTAXIS_Monitor_GUI/MyQtWidgets/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/QUANTAXIS_Monitor_GUI/ProgressDlgs/ProgressDlg_Timeout.py b/QUANTAXIS_Monitor_GUI/ProgressDlgs/ProgressDlg_Timeout.py deleted file mode 100644 index 9152a3003..000000000 --- a/QUANTAXIS_Monitor_GUI/ProgressDlgs/ProgressDlg_Timeout.py +++ /dev/null @@ -1,60 +0,0 @@ -from PyQt5.Qt import QLabel -from PyQt5.Qt import QDialog -from PyQt5.Qt import QMessageBox -from PyQt5.Qt import QHBoxLayout -from PyQt5.Qt import * -from PyQt5.QtGui import * -from PyQt5.QtCore import * - -from PyQt5.QtGui import QCloseEvent - -from abc import ABC, abstractmethod - -''' -谨慎使用, 调试的时候会锁死! 而且 多线程依赖 UI timer 不是很准确!! -移动父窗口 ,会死锁 -''' -class ProgressDlg_Timeout(QDialog): - def __init__(self, parent=None, timeOut = 5, userHint = None): - #parent not set to, none , 设置成parent 会死锁 - super(ProgressDlg_Timeout, self).__init__(parent) - self.setModal(True) - self.timeOut = timeOut - self.strMsg = userHint - self.initUI() - - def initUI(self): - #self.setWindowFlags(Qt.) - - self.label = QLabel(self) - self.label.setText('{} , 还剩 {} 秒'.format(self.strMsg, self.timeOut)) - - self.hLay = QHBoxLayout() - self.hLay.addWidget(self.label) - self.setLayout(self.hLay) - self.startTimer(1000) - pass - - #todo fixhere 调试的适合, 会锁死, 界面不会倒计时!!!!! - # 多线程依赖 UI timer 不是很准确!!调试的时候,容易死锁 - def timerEvent(self, a0: 'QTimerEvent'): - - if self.timeOut == 0: - self.close() - return - - self.timeOut = self.timeOut - 1 - self.label.setText('{} ,还剩 {} 秒'.format(self.strMsg, self.timeOut)) - - pass - - def closeEvent(self, event): - if self.timeOut == 0: - event.accept() - else: - msg = QMessageBox() - msg.setText("等待任务完成") - msg.exec() - event.ignore() - - pass \ No newline at end of file diff --git a/QUANTAXIS_Monitor_GUI/ProgressDlgs/ProgressDlg_WithThreading.py b/QUANTAXIS_Monitor_GUI/ProgressDlgs/ProgressDlg_WithThreading.py deleted file mode 100644 index ec3317e28..000000000 --- a/QUANTAXIS_Monitor_GUI/ProgressDlgs/ProgressDlg_WithThreading.py +++ /dev/null @@ -1,68 +0,0 @@ -from PyQt5.Qt import QLabel -from PyQt5.Qt import QDialog -from PyQt5.Qt import QMessageBox -from PyQt5.Qt import QHBoxLayout -from PyQt5.Qt import * -from PyQt5.QtGui import * -from PyQt5.QtCore import * - - -class ProgressDlg_WithQThread(QDialog): - def __init__(self, parent=None, qThreadObj = None, userHint = None, dlgTitle = None): - super(ProgressDlg_WithQThread, self).__init__(parent) - self.setModal(True) - self.qThreadObj = qThreadObj - self.userHint = userHint - - - if dlgTitle is not None: - self.setWindowTitle(dlgTitle) - self.initUI() - - def initUI(self): - #self.setWindowFlags() - self.label = QLabel(self) - self.label.setText(self.userHint) - - self.bnt = QPushButton(self) - self.bnt.setText("确定") - self.bnt.setMaximumWidth(150) - self.bnt.clicked.connect(self.Ok) - - self.hLay = QVBoxLayout(self) - self.hLay.setAlignment(Qt.AlignCenter) - self.hLay.addWidget(self.label) - self.hLay.addWidget(self.bnt) - self.setLayout(self.hLay) - self.startTimer(200) - - def startMyThread(self): - self.qThreadObj.strTaskRunningResult = "" - self.qThreadObj.strTaskRunningLog = "" - - self.qThreadObj.start() - - def timerEvent(self, a0: 'QTimerEvent'): - boolFinished = self.qThreadObj.isFinished() - if boolFinished: - strTaskRunningResult = self.qThreadObj.strTaskRunningResult - self.label.setText(strTaskRunningResult) - - else: - strTaskRunningLog = self.qThreadObj.strTaskRunningLog - self.label.setText(strTaskRunningLog) - - pass - - def closeEvent(self, event): - - boolFinished = self.qThreadObj.isFinished() - if boolFinished == True: - event.accept() - else: - QMessageBox.critical(self,"请等待!", ("等待任务完成!")) - event.ignore() - pass - - def Ok(self): - self.close() \ No newline at end of file diff --git a/QUANTAXIS_Monitor_GUI/ProgressDlgs/__init__.py b/QUANTAXIS_Monitor_GUI/ProgressDlgs/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/QUANTAXIS_Monitor_GUI/TasksByProcess/SubProcessFetchZJLX.py b/QUANTAXIS_Monitor_GUI/TasksByProcess/SubProcessFetchZJLX.py deleted file mode 100644 index 2f365a8e1..000000000 --- a/QUANTAXIS_Monitor_GUI/TasksByProcess/SubProcessFetchZJLX.py +++ /dev/null @@ -1,520 +0,0 @@ -import socket -import socketserver - -import re -from selenium import webdriver -import sys -from selenium.webdriver.common.keys import Keys -from selenium.webdriver.common.action_chains import ActionChains -from selenium.common.exceptions import WebDriverException -from selenium.webdriver.chrome.options import Options - - -import time -import datetime -import os -from QUANTAXIS.QAUtil import (DATABASE) - -''' -一种是 keep 长时间的 socket 连接 - -另一种是 操作完毕后主动关闭 socket 连接, 本服务程序 重新 accept 新的连接 -现在使用的是每次发送命令,后断开连接 - -客户端发送 下面4个命令 -start_chrome_driver -shutdown_chrome_driver -fetch_a_stock_data_to_mongodb -shutdown_process - - -''' - -##http://www.xiaomilu.top/archives/106 -#🛠todo fix 已到 QA_SU 目录下面 - -start_up_chrome_driver_error_message = "" - -def open_chrome_driver(): - - browser = None - strErrorMsg = "" - try: - - # todo 🛠 使用绝对路径 - print("chrome_driver 加载路径") - currentFile = __file__ - print(currentFile); - dirName = os.path.dirname(currentFile) - dirName1 = os.path.dirname(dirName) - dirName2 = os.path.dirname(dirName1) - print(dirName2) - print("chrome_driver 加载路径") - - - # chrome_options = Options() - # prefs = { - # 'profile.default_content_setting_values': { - # 'images': 2, # 禁用图片的加载 - # # 'javascript': 2 ##禁用js,可能会导致通过js加载的互动数抓取失效 - # } - # } - # chrome_options.add_experimental_option("prefs", prefs) - - - if sys.platform == 'darwin': - browser = webdriver.Chrome(dirName2 + '/QUANTAXIS_WEBDRIVER/macos/chromedriver') - elif sys.platform == 'win32': - browser = webdriver.Chrome(dirName2 + '/QUANTAXIS_WEBDRIVER/windows/chromedriver') - elif sys.platform == 'linux': - browser = webdriver.Chrome(dirName2 + './QUANTAXIS_WEBDRIVER/linux/chromedriver') - # todo 🛠 linux 下没有测试, linux 下 非gui环境下,用chrome headless driver - print("🎃") - print("🎃./selenium_driver/linux/chromedrive linux 平台上的的 🤖chromedriver 的路径") - print("🎃./selenium_driver/windows/chromedrive windows 平台上的的 🤖chromedriver 的路径") - print("🎃 https://npm.taobao.org/mirrors/chromedriver/ 🤖chromedriver下载地址") - print("🎃") - - - # browser.implicitly_wait(60) # 操作、获取元素时的隐式等待时间 - browser.set_page_load_timeout(60) - - except Exception as ee: - print(ee) - #nonlocal start_up_chrome_driver_error_message - strErrorMsg = ee.__str__() - - #todo fixhere 不能访问全局变量 ???? - start_up_chrome_driver_error_message = strErrorMsg - browser = None - - return browser - - -def do_open_web_page(strCode, browser): - - try: - urls = 'http://data.eastmoney.com/zjlx/{}.html'.format(strCode) - - ActionChains(browser).key_down(Keys.CONTROL).send_keys("w").key_up(Keys.CONTROL).perform() - ActionChains(browser).key_down(Keys.CONTROL).send_keys("w").key_up(Keys.CONTROL).perform() - ActionChains(browser).key_down(Keys.CONTROL).send_keys("w").key_up(Keys.CONTROL).perform() - - - browser.set_page_load_timeout(60) # throw a TimeoutException when thepage load time is more than 15 seconds - browser.get(urls) - browser.get_cookies() - browser.execute_script("window.scrollTo(0, document.body.scrollHeight);") - browser.minimize_window() - - print("😇Ok成功打开网页😇") - return "😇Ok成功打开网页😇" - except Exception as ee: - # nonlocal start_up_chrome_driver_error_message - strErrorMsg = ee.__str__() - print(ee) - return strErrorMsg - - -#新添加到数据库到记录 -new_rec = 0 - -def praseWebPage(code, browser, connection): - try: - - #计算时间 - nowTime0 = datetime.datetime.now() - - - #1########################################################################################################## - #nowTime_find_date_table_start = datetime.datetime.now() - #1########################################################################################################## - - # result = [] - zjlxtable = browser.find_element_by_id('content_zjlxtable') - table_elements = zjlxtable.find_element_by_tag_name('table') - - table_header = table_elements.find_elements_by_tag_name('thead') - # todo 🛠 不知道为何,tbody 标签那不到数据 - table_body = table_elements.find_elements_by_tag_name('tbody') - - # chrome debug copy xpath - table_body2 = browser.find_elements_by_xpath('//*[@id="dt_1"]/tbody') - - head1_list = [] - head2_list = [] - - if isinstance(table_header, list) == True: - # print(table_header[0]) - # print(table_header[0].text) - - table_header_row = table_header[0].find_elements_by_tag_name('tr') - - #assert (len(table_header_row) == 2) - if (len(table_header_row) == 2) == False: - raise WebDriverException("网页数据错误1") - - table_head_name1 = table_header_row[0].find_elements_by_tag_name('th') - table_head_name2 = table_header_row[1].find_elements_by_tag_name('th') - - for i in range(len(table_head_name1)): - head_name = table_head_name1[i].get_attribute("innerHTML") - head1_list.append(head_name) - # print(table_head_name1[i].get_attribute("value")) - - for i in range(len(table_head_name2)): - head_name = table_head_name2[i].get_attribute("innerHTML") - head2_list.append(head_name) - # print(table_head_name1[i].get_attribute("value")) - else: - # raise NoSuchElementException - print("error !!!!!!!!") - raise WebDriverException("网页数据错误8") - - #1########################################################################################################## - #nowTime_find_date_table_end = datetime.datetime.now() - #secondsUsed_for_find_date_table = (nowTime_find_date_table_end - nowTime_find_date_table_start).seconds - #print("❤️计算时间1 查找table_body2 list 使用了%d秒 ️🖼👍"%secondsUsed_for_find_date_table) - #1########################################################################################################## - - - #2########################################################################################################## - #nowTime_loop_list_for_table_body2_start = datetime.datetime.now() - #2########################################################################################################## - - row1_list = [] - if isinstance(table_body2, list) == True: - - #3########################################################################################################## - #t0_find_element_by_tag_start = datetime.datetime.now() - #3########################################################################################################## - - table_body_row = table_body2[0].find_elements_by_tag_name('tr') - print("🖼 成功获取 %d 天的资金流向数据️" % (len(table_body_row))) - row_length = len(table_body_row) - - #3########################################################################################################## - #t0_find_element_by_tag_end = datetime.datetime.now() - #t0_find_element_by_tag_used_second= (t0_find_element_by_tag_end - t0_find_element_by_tag_start).microseconds - #print("❤️计算时间0 find_elements_by_tag_name tr 使用了%d m秒 ️🖼👍" % t0_find_element_by_tag_used_second) - #3########################################################################################################## - - - for i in range(row_length): - - #4########################################################################################################## - #t4_find_element_by_tag_start = datetime.datetime.now() - #4########################################################################################################## - - table_body_cell = table_body_row[i].find_elements_by_tag_name('td') - #assert (len(table_body_cell) == 13) - if (len(table_body_cell) == 13) == False: - raise WebDriverException("网页数据错误2") - - #4########################################################################################################## - #t4_find_element_by_tag_end = datetime.datetime.now() - #t4_find_element_by_tag_used_second = (t4_find_element_by_tag_end - t4_find_element_by_tag_start).microseconds - #print("❤️计算时间4 find_elements_by_tag_name td 使用了%d m秒 ️🖼👍" % t4_find_element_by_tag_used_second) - #4########################################################################################################## - - #5########################################################################################################## - #t5_get_table_data_start = datetime.datetime.now() - #5########################################################################################################## - dict_row = {} - dict_row['stock_code'] = code - - dict_row['date'] = table_body_cell[0].text - dict_row['zljll_je_wy'] = table_body_cell[1].text - dict_row['zljll_jzb_bfb'] = table_body_cell[2].text - dict_row['cddjll_je_wy'] = table_body_cell[3].text - dict_row['cddjll_je_jzb'] = table_body_cell[4].text - dict_row['ddjll_je_wy'] = table_body_cell[5].text - dict_row['ddjll_je_jzb'] = table_body_cell[6].text - dict_row['zdjll_je_wy'] = table_body_cell[7].text - dict_row['zdjll_je_jzb'] = table_body_cell[8].text - dict_row['xdjll_je_wy'] = table_body_cell[9].text - dict_row['xdjll_je_jzb'] = table_body_cell[10].text - dict_row['close_price'] = table_body_cell[11].text - dict_row['change_price'] = table_body_cell[12].text - - row1_list.append(dict_row) - - #5########################################################################################################## - #t5_get_table_data_end = datetime.datetime.now() - #t5_get_table_data_end_used_second = (t5_get_table_data_end - t5_get_table_data_start).microseconds - #print("❤️计算时间5 get_table_data 使用了%d m秒 ️🖼👍" % t5_get_table_data_end_used_second) - #5########################################################################################################## - - # todo 🛠 循环获取网页速度非常慢, 进一步学习 selenium 的操作, 批量一次获取数据 - iPct = round((i / row_length) * 100.0) - #s1 = "\r读取数据%d%%[%s%s]" % (iPct, "🐢" * iPct, " " * (100 - iPct)) - #sys.stdout.write(s1) - #sys.stdout.flush() - - #6########################################################################################################## - #t6_send_newwork_date_start = datetime.datetime.now() - #6############################################################ - strMsg0 = "state@progress@%f"%iPct - #print("🦀 网页进度 🦀",strMsg0) - bytes_content = strMsg0.encode() - bytes_content = bytes_content.zfill(128) - #assert (len(bytes_content) == 128) - if (len(bytes_content) == 128) == False: - raise WebDriverException("网页数据错误3") - - # 🛠todo fix 128 个byte 很傻 - connection.sendall(bytes_content) - # - ############################################################# - strMsg0 = "state@hearbeat@代码:{}日期:{}".format(code, dict_row['date']) - bytes_content = strMsg0.encode() - bytes_content = bytes_content.zfill(128) - #assert (len(bytes_content) == 128) - if (len(bytes_content) == 128) == False: - raise WebDriverException("网页数据错误4") - - # 🛠todo fix 128 个byte 很傻 - connection.sendall(bytes_content) - #6############################################################ - #t6_send_newwork_date_end = datetime.datetime.now() - #t6_send_newwork_date_used_second = (t6_send_newwork_date_end - t6_send_newwork_date_start).microseconds - #print("❤️计算时间6 send_newwork_date 使用了%d m秒 ️🖼👍" % t6_send_newwork_date_used_second) - #6########################################################################################################## - # v = [] - # v.append() # 日期 - # v.append(table_body_cell[1].text) # 收盘价 - # v.append(table_body_cell[2].text) # 涨跌幅 - # v.append(table_body_cell[3].text) # 主力净流入_净额(万元) - # v.append(table_body_cell[4].text) # 主力净流入_净占比(%) - # v.append(table_body_cell[5].text) # 超大单净流入_净额(万元) - # v.append(table_body_cell[6].text) # 超大单净流入_净占比(%) - # v.append(table_body_cell[7].text) # 大单净流入_净额(万元) - # v.append(table_body_cell[8].text) # 大单净流入_净占比(%) - # v.append(table_body_cell[9].text) # 中单净流入_净额(万元) - # v.append(table_body_cell[10].text)# 中单净流入_净占比(%) - # v.append(table_body_cell[11].text)# 小单净流入_净额(万元) - # v.append(table_body_cell[12].text)# 小单净流入_净占比(%) - - #print('总体耗时间: %f' % t) - - else: - #raise NoSuchElementException - #print("error !!!!!!!!") - raise WebDriverException("网页数据错误23") - pass - - #2########################################################################################################## - #nowTime_loop_list_for_table_body2_end = datetime.datetime.now() - #secondsUsed_for_loop = (nowTime_loop_list_for_table_body2_end - nowTime_loop_list_for_table_body2_start).seconds - #print("❤️❤️🖼 循环获取 列表 使用了 %d秒 ️🖼👍👍"%secondsUsed_for_loop) - #2########################################################################################################## - - # assert (len(row1_list) != 0) - # assert (len(head1_list) != 0) - # assert (len(head2_list) != 0) - - ActionChains(browser).key_down(Keys.CONTROL).send_keys("w").key_up(Keys.CONTROL).perform() - - ##1########################################################################################################## - #nowTime1 = datetime.datetime.now() - #secondsUsed = (nowTime1 - nowTime0).seconds - #print("❤️❤️🖼 完成网页解析使用了%d秒 ️🖼👍👍"%secondsUsed) - #1########################################################################################################## - - client = DATABASE - coll_stock_zjlx = client.eastmoney_stock_zjlx - - print("🥕准备写入mongodb 🎞保存数据库 eastmoney_stock_zjlx") - - global new_rec - new_rec = 0 - row_length = len(row1_list) - for i in range(row_length): - - #https://www.jianshu.com/p/53cf61220828 - aRec = row1_list[i] - - # 🛠todo 当天结束后,获取当天的资金流相,当天的资金流向是瞬时间点的 - ret = coll_stock_zjlx.find_one(aRec) - if ret == None: - coll_stock_zjlx.insert_one(aRec) - new_rec = new_rec + 1 - #print("🤑 插入新的记录 ", aRec) - pass - else: - #print("😵 记录已经存在 ", ret) - pass - - - iPct = round((i / row_length) * 100.0) - ############################################################# - strMsg0 = "state@progress@%f" % iPct - # print("🦀 网页进度 🦀",strMsg0) - bytes_content = strMsg0.encode() - bytes_content = bytes_content.zfill(128) - #assert (len(bytes_content) == 128) - # 🛠todo fix 128 个byte 很傻 - connection.sendall(bytes_content) - - # ############################################################# - # strMsg0 = "state@hearbeat@代码:{}日期:{}".format(code, dict_row['date']) - # bytes_content = strMsg0.encode() - # bytes_content = bytes_content.zfill(128) - # assert (len(bytes_content) == 128) - # # 🛠todo fix 128 个byte 很傻 - # connection.sendall(bytes_content) - # ############################################################# - - print("🖼 🎞写入数据库 🐌 新纪录{}条 💹 ".format(new_rec)) - - return ["😇Ok成功解析网页😇",new_rec] - - except WebDriverException as ee: - print("❌ read_east_money_page_zjlx_to_sqllite 读取网页数据错误 🤮") - - strErroMsg = ee.__str__() - #errorMsg0 = "finished@code {} msg{}".format(code, ee.__str__()) - print(strErroMsg) - - # bytes_content = errorMsg0.encode() - # bytes_content = bytes_content.zfill(512) - # assert (len(bytes_content) == 512) - # # 🛠todo fix 固定512 个byte 很傻 - # conn.sendall(bytes_content) - - ActionChains(browser).key_down(Keys.CONTROL).send_keys("w").key_up(Keys.CONTROL).perform() - ActionChains(browser).key_down(Keys.CONTROL).send_keys("w").key_up(Keys.CONTROL).perform() - ActionChains(browser).key_down(Keys.CONTROL).send_keys("w").key_up(Keys.CONTROL).perform() - - return [strErroMsg,new_rec] - - -working_browser = None - - -def unpackParam(data): - global cmdArry - cmdString = data.decode('utf-8'); - cmdArry = cmdString.split('@') - cmdArry[0] = cmdArry[0].strip('0') - return cmdArry - -def send_execute_result(connection, strMsg0): - bytes_content = strMsg0.encode() - bytes_content = bytes_content.zfill(128) - assert (len(bytes_content) == 128) - # 🛠todo fix 128 个byte 很傻 - connection.sendall(bytes_content) - -def do_shutdown_process(data,connection): - strMsg0 = "state@shutdown_procceed" - send_execute_result(connection, strMsg0) - print("🕹>>>>>>finish do shutdown_process>>>>>>>") - connection.close() - -def do_startup_chrome(data, connection): - global working_browser - working_browser = open_chrome_driver() - if working_browser is not None: - strMsg0 = "state@start_chrome_driver_ok" - send_execute_result(connection,strMsg0) - print("🕹>>>>>>do start_chrome_driver_ok>>>>>>>✅"); - else: - strMsg0 = "state@start_chrome_driver_failed@%s" % start_up_chrome_driver_error_message - send_execute_result(connection,strMsg0) - print("🕹>>>>>>do start_chrome_driver_failed>>>>>>>❌"); - pass - - - -def do_shutdown_chrome(data, connection): - global working_browser - if working_browser is not None: - working_browser.quit() - strMsg0 = "state@shutdown_chrome_driver_ok" - send_execute_result(connection,strMsg0) - print("🕹>>>>>>do shutdown_chrome_driver_ok>>>>>>>✅"); - else: - strMsg0 = "state@shutdown_chrome_driver_failed" - send_execute_result(connection, strMsg0) - print("🕹>>>>>>do shutdown_chrome_driver_failed>>>>>>>❌"); - pass - - - -def do_fetch_web_page(data,connection,strcode,): - global working_browser - retV = do_open_web_page(strcode, working_browser) - if retV == "😇Ok成功打开网页😇": - strMsg0 = "state@fetch_a_stock_data_to_mongodb_open_web_page_ok" - send_execute_result(connection, strMsg0) - print("🕹>>>>>>do fetch_a_stock_data_to_mongodb_open_web_page_ok>>>>>>>✅"); - - - retV2 = praseWebPage(strCode,working_browser,connection) - if retV2[0] == "😇Ok成功解析网页😇": - - strMsg0 = "state@fetch_a_stock_data_to_mongodb_prase_web_page_ok@{}".format(retV2[1]) - send_execute_result(connection, strMsg0) - print("🕹>>>>>>do fetch_a_stock_data_to_mongodb_prase_web_page_ok>>>>>>>✅"); - - else: - strMsg0 = "state@fetch_a_stock_data_to_mongodb_prase_web_page_failed@{}".format(retV2[1]) - send_execute_result(connection, strMsg0) - print("🕹>>>>>>do fetch_a_stock_data_to_mongodb_prase_web_page_failed>>>>>>>✅"); - - else: - strMsg0 = "state@fetch_a_stock_data_to_mongodb_open_web_page_failed@{}".format(retV) - send_execute_result(connection, strMsg0) - print("🕹>>>>>>do fetch_a_stock_data_to_mongodb_open_web_page_failed msg:{}>>>>>>>✅".format(retV)); - pass - - - -if __name__ == '__main__': - - sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - port = sys.argv[1] - - # Bind the socket to the port - server_address = ('localhost', int(port)) - print('starting up on {} port {}'.format(*server_address)) - sock.bind(server_address) - - # Listen for incoming connections - sock.listen(1) - - #accept for the initial connecton - connection, client_address = sock.accept() - - while True: - connection, client_address = sock.accept() - - data = connection.recv(128) - if data: - print('received {!r}'.format(data)) - cmdArry = unpackParam(data) - - if cmdArry[0] == "start_chrome_driver": - do_startup_chrome(data, connection) - continue - - if cmdArry[0] == "shutdown_chrome_driver": - do_shutdown_chrome(data,connection) - continue - - if cmdArry[0] == 'fetch_a_stock_data_to_mongodb': - strCode = cmdArry[1]; - do_fetch_web_page(data,connection,strCode) - continue - - if cmdArry[0] == 'shutdown_process': - do_shutdown_process(data,connection) - break - - else: - continue - - - sock.close() - print("🕹>>>>>>进程结束了 with port {}>>>>>>>".format(port)); \ No newline at end of file diff --git a/QUANTAXIS_Monitor_GUI/TasksByProcess/SubSeleniumProcess_not_used.py b/QUANTAXIS_Monitor_GUI/TasksByProcess/SubSeleniumProcess_not_used.py deleted file mode 100644 index f7c7dc451..000000000 --- a/QUANTAXIS_Monitor_GUI/TasksByProcess/SubSeleniumProcess_not_used.py +++ /dev/null @@ -1,357 +0,0 @@ -import socket -import re -from selenium import webdriver -import sys -from selenium.webdriver.common.keys import Keys -from selenium.webdriver.common.action_chains import ActionChains -from selenium.common.exceptions import WebDriverException - -import time - -import os -from QUANTAXIS.QAUtil import (DATABASE) - -''' -https://www.cnblogs.com/taurusfy/p/8464602.html -''' - -#🛠todo fix 已到 QA_SU 目录下面 -def open_chrome_driver(): - - currentFile = __file__ - print(currentFile); - - dirName = os.path.dirname(currentFile) - dirName1 = os.path.dirname(dirName) - dirName2 = os.path.dirname(dirName1) - print(dirName2) - - - if sys.platform == 'darwin': - browser = webdriver.Chrome(dirName2 + '/QUANTAXIS_WEBDRIVER/macos/chromedriver') - elif sys.platform == 'win32': - browser = webdriver.Chrome(dirName2 + '/QUANTAXIS_WEBDRIVER/windows/chromedriver') - elif sys.platform == 'linux': - browser = webdriver.Chrome(dirName2 + './QUANTAXIS_WEBDRIVER/linux/chromedriver') - # todo 🛠 linux 下没有测试, linux 下 非gui环境下,用chrome headless driver - print("🎃") - print("🎃./selenium_driver/linux/chromedrive linux 平台上的的 🤖chromedriver 的路径") - print("🎃./selenium_driver/windows/chromedrive windows 平台上的的 🤖chromedriver 的路径") - print("🎃 https://npm.taobao.org/mirrors/chromedriver/ 🤖chromedriver下载地址") - print("🎃") - return browser - -def close_chrome_dirver(browser): - browser.quit() - - -def crawly_code(code=None, conn = None, browser = None): - - #关闭先前的页面 - ActionChains(browser).key_down(Keys.CONTROL).send_keys("w").key_up(Keys.CONTROL).perform() - ActionChains(browser).key_down(Keys.CONTROL).send_keys("w").key_up(Keys.CONTROL).perform() - ActionChains(browser).key_down(Keys.CONTROL).send_keys("w").key_up(Keys.CONTROL).perform() - ActionChains(browser).key_down(Keys.CONTROL).send_keys("w").key_up(Keys.CONTROL).perform() - ActionChains(browser).key_down(Keys.CONTROL).send_keys("w").key_up(Keys.CONTROL).perform() - - - urls = 'http://data.eastmoney.com/zjlx/{}.html'.format(code) - pa = re.compile(r'\w+') - - # 启动chrome - strMsg0 = "logging@开启代理游览器获取数据{}".format(code) - bytes_content = strMsg0.encode() - bytes_content = bytes_content.zfill(512) - # 🛠todo fix 固定512 个byte 很傻 - assert(len(bytes_content) == 512) - conn.sendall(bytes_content) - - - - browser.set_page_load_timeout(30) # throw a TimeoutException when thepage load time is more than 15 seconds - browser.minimize_window() - - bytes_content = b"progress@100" - bytes_content =bytes_content.zfill(512) - # 🛠todo fix 固定512 个byte 很傻 - assert(len(bytes_content) == 512) - conn.sendall(bytes_content) - - browser.get(urls) - - strMsg0= "logging@页面成功打开{}OK, 解析网页中".format(code) - bytes_content = strMsg0.encode() - bytes_content = bytes_content.zfill(512) - # 🛠todo fix 固定512 个byte 很傻 - assert (len(bytes_content) == 512) - conn.sendall(bytes_content) - - try: - # result = [] - zjlxtable = browser.find_element_by_id('content_zjlxtable') - table_elements = zjlxtable.find_element_by_tag_name('table') - - table_header = table_elements.find_elements_by_tag_name('thead') - # todo 🛠 不知道为何,tbody 标签那不到数据 - table_body = table_elements.find_elements_by_tag_name('tbody') - - # chrome debug copy xpath - table_body2 = browser.find_elements_by_xpath('//*[@id="dt_1"]/tbody') - - head1_list = [] - head2_list = [] - - if isinstance(table_header, list) == True: - # print(table_header[0]) - # print(table_header[0].text) - - table_header_row = table_header[0].find_elements_by_tag_name('tr') - - assert (len(table_header_row) == 2) - - table_head_name1 = table_header_row[0].find_elements_by_tag_name('th') - table_head_name2 = table_header_row[1].find_elements_by_tag_name('th') - - for i in range(len(table_head_name1)): - head_name = table_head_name1[i].get_attribute("innerHTML") - head1_list.append(head_name) - # print(table_head_name1[i].get_attribute("value")) - - for i in range(len(table_head_name2)): - head_name = table_head_name2[i].get_attribute("innerHTML") - head2_list.append(head_name) - # print(table_head_name1[i].get_attribute("value")) - else: - # raise NoSuchElementException - print("error !!!!!!!!") - - row1_list = [] - if isinstance(table_body2, list) == True: - - table_body_row = table_body2[0].find_elements_by_tag_name('tr') - print("🖼 成功获取 %d 天的资金流向数据️" % (len(table_body_row))) - - t0 = time.clock() - - row_length = len(table_body_row) - for i in range(row_length): - table_body_cell = table_body_row[i].find_elements_by_tag_name('td') - assert (len(table_body_cell) == 13) - - dict_row = {} - dict_row['stock_code'] = code - - dict_row['date'] = table_body_cell[0].text - dict_row['zljll_je_wy'] = table_body_cell[1].text - dict_row['zljll_jzb_bfb'] = table_body_cell[2].text - dict_row['cddjll_je_wy'] = table_body_cell[3].text - dict_row['cddjll_je_jzb'] = table_body_cell[4].text - dict_row['ddjll_je_wy'] = table_body_cell[5].text - dict_row['ddjll_je_jzb'] = table_body_cell[6].text - dict_row['zdjll_je_wy'] = table_body_cell[7].text - dict_row['zdjll_je_jzb'] = table_body_cell[8].text - dict_row['xdjll_je_wy'] = table_body_cell[9].text - dict_row['xdjll_je_jzb'] = table_body_cell[10].text - dict_row['close_price'] = table_body_cell[11].text - dict_row['change_price'] = table_body_cell[12].text - - row1_list.append(dict_row) - - # todo 🛠 循环获取网页速度非常慢, 进一步学习 selenium 的操作, 批量一次获取数据 - iPct = round((i / row_length) * 100.0) - #s1 = "\r读取数据%d%%[%s%s]" % (iPct, "🐢" * iPct, " " * (100 - iPct)) - #sys.stdout.write(s1) - #sys.stdout.flush() - - bytes_content = b"progress@%f"%iPct - bytes_content = bytes_content.zfill(512) - assert (len(bytes_content) == 512) - # 🛠todo fix 固定512 个byte 很傻 - conn.sendall(bytes_content) - - - # 不发送给主进程, - # strData = json.dumps(dict_row) - # strData = "data@%s" % strData - # bytes_content = str.encode(strData, encoding='utf-8') - # bytes_content = bytes_content.zfill(512) - # assert (len(bytes_content) == 512) - # # 🛠todo fix 固定512 个byte 很傻 - # conn.sendall(bytes_content) - - strMsg0 = "logging@股票资金流向{}, 日期数据 {} OK".format(code, dict_row['date']) - bytes_content = strMsg0.encode() - bytes_content = bytes_content.zfill(512) - assert (len(bytes_content) == 512) - # 🛠todo fix 固定512 个byte 很傻 - conn.sendall(bytes_content) - - # v = [] - # v.append() # 日期 - # v.append(table_body_cell[1].text) # 收盘价 - # v.append(table_body_cell[2].text) # 涨跌幅 - # v.append(table_body_cell[3].text) # 主力净流入_净额(万元) - # v.append(table_body_cell[4].text) # 主力净流入_净占比(%) - # v.append(table_body_cell[5].text) # 超大单净流入_净额(万元) - # v.append(table_body_cell[6].text) # 超大单净流入_净占比(%) - # v.append(table_body_cell[7].text) # 大单净流入_净额(万元) - # v.append(table_body_cell[8].text) # 大单净流入_净占比(%) - # v.append(table_body_cell[9].text) # 中单净流入_净额(万元) - # v.append(table_body_cell[10].text)# 中单净流入_净占比(%) - # v.append(table_body_cell[11].text)# 小单净流入_净额(万元) - # v.append(table_body_cell[12].text)# 小单净流入_净占比(%) - - t = time.clock() - t0 - #print('总体耗时间: %f' % t) - - else: - #raise NoSuchElementException - #print("error !!!!!!!!") - pass - - assert (len(row1_list) != 0) - assert (len(head1_list) != 0) - assert (len(head2_list) != 0) - - ActionChains(browser).key_down(Keys.CONTROL).send_keys("w").key_up(Keys.CONTROL).perform() - - #print("🖼 完成获取数据,关闭chromedrive ,") - - strMsg0 = "logging@准备写入数据库{}".format(code) - bytes_content = strMsg0.encode() - bytes_content = bytes_content.zfill(512) - assert (len(bytes_content) == 512) - # 🛠todo fix 固定512 个byte 很傻 - conn.sendall(bytes_content) - - client = DATABASE - coll_stock_zjlx = client.eastmoney_stock_zjlx - - print("🥕准备写入mongodb 🎞保存数据库 ", 'eastmoney_stock_zjlx') - - new_rec = 0 - for i in range(len(row1_list)): - aRec = row1_list[i] - - # 🛠todo 当天结束后,获取当天的资金流相,当天的资金流向是瞬时间点的 - ret = coll_stock_zjlx.find_one(aRec) - if ret == None: - coll_stock_zjlx.insert_one(aRec) - new_rec = new_rec + 1 - print("🤑 插入新的记录 ", aRec) - - # strMsg0 = "logging@写入{}".format(aRec) - # bytes_content = strMsg0.encode() - # bytes_content = bytes_content.zfill(512) - # assert (len(bytes_content) == 512) - # # 🛠todo fix 固定512 个byte 很傻 - # conn.sendall(bytes_content) - else: - print("😵 记录已经存在 ", ret) - - # strMsg0 = "logging@记录已经存在{}".format(aRec) - # bytes_content = strMsg0.encode() - # bytes_content = bytes_content.zfill(512) - # assert (len(bytes_content) == 512) - # # 🛠todo fix 固定512 个byte 很傻 - # conn.sendall(bytes_content) - pass - - print("🖼 🎞写入数据库 🐌 新纪录 ", new_rec, "条 💹 ") - - strMsg0 = "logging@{}写入数据库新纪录{}条".format(code,new_rec) - bytes_content = strMsg0.encode() - bytes_content = bytes_content.zfill(512) - assert (len(bytes_content) == 512) - # 🛠todo fix 固定512 个byte 很傻 - conn.sendall(bytes_content) - - - except WebDriverException as ee: - print("❌ read_east_money_page_zjlx_to_sqllite 读取网页数据错误 🤮") - - errorMsg0 = "finished@code {} msg{}".format(code,ee.__str__()) - - bytes_content = errorMsg0.encode() - bytes_content = bytes_content.zfill(512) - assert (len(bytes_content) == 512) - # 🛠todo fix 固定512 个byte 很傻 - conn.sendall(bytes_content) - - ActionChains(browser).key_down(Keys.CONTROL).send_keys("w").key_up(Keys.CONTROL).perform() - ActionChains(browser).key_down(Keys.CONTROL).send_keys("w").key_up(Keys.CONTROL).perform() - ActionChains(browser).key_down(Keys.CONTROL).send_keys("w").key_up(Keys.CONTROL).perform() - - return - - okMsg0 = "finished@code {} 获取完成 OK".format(code) - bytes_content = okMsg0.encode() - bytes_content =bytes_content.zfill(512) - assert(len(bytes_content) == 512) - # 🛠todo fix 固定512 个byte 很傻 - conn.sendall(bytes_content) - - - - - -if __name__ == '__main__': - # Create a TCP/IP socket - sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - - port = sys.argv[1] - - # Bind the socket to the port - server_address = ('localhost', int(port)) - print('starting up on {} port {}'.format(*server_address)) - sock.bind(server_address) - - # Listen for incoming connections - sock.listen(1) - - browser = open_chrome_driver(); - browser.minimize_window() - - - while True: - # Wait for a connection - print('waiting for a connection') - connection, client_address = sock.accept() - try: - print('connection from', client_address) - - strMsg0 = "logging@成功建立socket服务,开启Chrome驱动" - bytes_content = strMsg0.encode() - bytes_content = bytes_content.zfill(512) - assert (len(bytes_content) == 512) - # 🛠todo fix 固定512 个byte 很傻 - connection.sendall(bytes_content) - - # Receive the data in small chunks and retransmit it - while True: - data = connection.recv(11) - print('received {!r}'.format(data)) - if data: - cmdString = data.decode('utf-8'); - cmdArry = cmdString.split(':') - print(cmdArry) - #print('sending data back to the client') - #connection.sendall(data) - - if cmdArry[0] == 'read': - # do the lone time get the data , report the status - crawly_code(code = cmdArry[1], conn= connection, browser= browser); - break - #等待获取结束 - if cmdArry[0] == 'shutdown': - print(" shutdown 命令收到, 退出进程!") - ActionChains(browser).key_down(Keys.COMMAND).send_keys("Q").key_up(Keys.CONTROL).perform() - connection.close() - os._exit(88) - else: - print('no data from', client_address) - break - - finally: - # Clean up the connection - connection.close() diff --git a/QUANTAXIS_Monitor_GUI/TasksByProcess/__init__.py b/QUANTAXIS_Monitor_GUI/TasksByProcess/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/QUANTAXIS_Monitor_GUI/TasksByThreading/QA_Gui_DateFetch_Task.py b/QUANTAXIS_Monitor_GUI/TasksByThreading/QA_Gui_DateFetch_Task.py deleted file mode 100644 index ea8aef841..000000000 --- a/QUANTAXIS_Monitor_GUI/TasksByThreading/QA_Gui_DateFetch_Task.py +++ /dev/null @@ -1,737 +0,0 @@ - -import time - -from PyQt5.QtCore import * -from PyQt5.QtGui import * -from PyQt5.QtWidgets import * -from PyQt5 import QtCore - - -from QUANTAXIS.QASU.save_tdx import (QA_SU_save_stock_day, - QA_SU_save_stock_week, - QA_SU_save_stock_month, - QA_SU_save_stock_year, - QA_SU_save_stock_xdxr, - QA_SU_save_stock_min, - QA_SU_save_index_day, - QA_SU_save_index_min, - QA_SU_save_etf_day, - QA_SU_save_etf_min, - QA_SU_save_stock_list, - QA_SU_save_stock_block, - QA_SU_save_stock_info, - QA_SU_save_stock_transaction, - QA_SU_save_option_day) - - -from QUANTAXIS.QAUtil import DATABASE - -''' - -https://martinfitzpatrick.name/article/multithreading-pyqt-applications-with-qthreadpool/ - QThread -''' - - -class QA_GUI_Date_Fetch_Task(QThread): - #todo fix here 不会执行 __init__的 QThread 是一个很特别的对象。 - # - #def __int__(self, qParentWidget): - # 初始化函数,默认 - # super(QA_GUI_Date_Fetch_Task, self).__init__() - # self.qParentWidget = qParentWidget; - - # abstract method, 线程工作的地方 - def run(self): - pass - - # 定义一个信号, 更新任务进度 - trigger_new_log = pyqtSignal(str) - trigger_new_progress = pyqtSignal(int) - - trigger_start_task_begin = pyqtSignal(str) - trigger_start_task_done = pyqtSignal(str) - - #abstract method ? - def connectSignalSlot(self): - self.trigger_new_log.connect(self.updateLogTriggerHandler) - self.trigger_new_progress.connect(self.updateProgressTriggerHandler) - self.trigger_start_task_begin.connect(self.startTaskTriggerHandler) - self.trigger_start_task_done.connect(self.doneTaskTriggerHandler) - - def setLoggingUIWidget(self, logDisplay): - self.logDisplay = logDisplay - - def setProgressUIWidget(self, qProgressBar): - self.qProgressBar = qProgressBar - - def setCheckboxUIWidget(self, qCheckBox): - self.qCheckBox = qCheckBox - - - #abstract method - def changeRunningTaskColor0(self, qColor=None): - palette = self.qCheckBox.palette() - - if qColor == None: - palette.setColor(QPalette.Active, QPalette.WindowText, Qt.black) - else: - palette.setColor(QPalette.Active, QPalette.WindowText, qColor) - - self.qCheckBox.setPalette(palette) - pass - - - #abstract method - def updateLogTriggerHandler(self): - pass - - #abstract method - def updateProgressTriggerHandler(self): - pass - - #abstract method - def startTaskTriggerHandler(self): - pass - - #abstract method - def doneTaskTriggerHandler(self): - pass - - - -class QA_GUI_DateFetch_SU_job01_stock_day(QA_GUI_Date_Fetch_Task): - - # todo fix here 不会执行 __init__的 QThread 是一个很特别的对象。 - #def __int__(self, qParentWidget): - #super(QA_GUI_DateFetch_SU_job01_stock_day, self).__init__() - #self.qCheckBox = qParentWidget.qCheckBoxJob01_save_stock_day - #self.qProgressBar = qParentWidget.qProgressJob01_save_stock_day; - - def startTaskTriggerHandler(self, info_str): - self.changeRunningTaskColor0(QtCore.Qt.red) - pass - - def doneTaskTriggerHandler(self, info_str): - # - self.changeRunningTaskColor0(QtCore.Qt.black) - pass - - def updateLogTriggerHandler(self, log): - #print("append task log emite triggered!", log); - #self.logDisplay.append(log) - if log and log.strip(): - rowCount = self.logDisplay.rowCount() - newItem1 = QTableWidgetItem(log) - newItem2 = QTableWidgetItem("QA_SU_save_stock_day") - self.logDisplay.setRowCount(rowCount+1) - self.logDisplay.setItem(rowCount,0,newItem1) - self.logDisplay.setItem(rowCount,1,newItem2) - #self.logDisplay.scrollToBottom() - - pass - - def updateProgressTriggerHandler(self, progress): - # print('update task progress ', progress); - self.qProgressBar.setValue(progress) - pass - - - # thread is working here - def run(self): - self.trigger_start_task_begin.emit("begin") - QA_SU_save_stock_day(client=DATABASE, ui_log=self.trigger_new_log, ui_progress= self.trigger_new_progress) - self.trigger_start_task_done.emit("end") - -###################################################################################################################\ - -class QA_GUI_DateFetch_SU_job01_stock_week(QA_GUI_Date_Fetch_Task): - # 🛠todo fix here 不会执行 __init__的 QThread 是一个很特别的对象。 - # def __int__(self): - # # 初始化函数,默认 - # super(QA_GUI_DateFetch_SU_job01_stock_week, self).__init__() - - def startTaskTriggerHandler(self, info_str): - self.changeRunningTaskColor0(QtCore.Qt.yellow) - pass - - def doneTaskTriggerHandler(self, info_str): - # - self.changeRunningTaskColor0(QtCore.Qt.green) - pass - - def updateLogTriggerHandler(self, log): - # print("append task log emite triggered!", log); - # self.logDisplay.append(log) - if log and log.strip(): - rowCount = self.logDisplay.rowCount() - newItem1 = QTableWidgetItem(log) - newItem2 = QTableWidgetItem("QA_SU_save_stock_week") - self.logDisplay.setRowCount(rowCount + 1) - self.logDisplay.setItem(rowCount, 0, newItem1) - self.logDisplay.setItem(rowCount, 1, newItem2) - #self.logDisplay.scrollToBottom() - - pass - - def updateProgressTriggerHandler(self, progress): - # print('update task progress ', progress); - self.qProgressBar.setValue(progress) - pass - - def run(self): - self.trigger_start_task_begin.emit("begin") - QA_SU_save_stock_week(client=DATABASE, ui_log= self.trigger_new_log, ui_progress= self.trigger_new_progress) - self.trigger_start_task_done.emit("end") - pass - -###################################################################################################################\ - -class QA_GUI_DateFetch_SU_job01_stock_month(QA_GUI_Date_Fetch_Task): - # todo fix here 不会执行 __init__的 QThread 是一个很特别的对象。 - # def __int__(self): - # # 初始化函数,默认 - # super(QA_GUI_DateFetch_SU_job01_stock_month, self).__init__() - - - def startTaskTriggerHandler(self, info_str): - self.changeRunningTaskColor0(QtCore.Qt.blue) - pass - - def doneTaskTriggerHandler(self, info_str): - # - self.changeRunningTaskColor0(QtCore.Qt.green) - pass - - def updateLogTriggerHandler(self, log): - # print("append task log emite triggered!", log); - # self.logDisplay.append(log) - if log and log.strip(): - rowCount = self.logDisplay.rowCount() - newItem1 = QTableWidgetItem(log) - newItem2 = QTableWidgetItem("QA_SU_save_stock_month") - self.logDisplay.setRowCount(rowCount + 1) - self.logDisplay.setItem(rowCount, 0, newItem1) - self.logDisplay.setItem(rowCount, 1, newItem2) - #self.logDisplay.scrollToBottom() - - pass - - def updateProgressTriggerHandler(self, progress): - # print('update task progress ', progress); - self.qProgressBar.setValue(progress) - pass - - def run(self): - self.trigger_start_task_begin.emit("begin") - QA_SU_save_stock_month(client=DATABASE, ui_log= self.trigger_new_log, ui_progress= self.trigger_new_progress) - self.trigger_start_task_done.emit("end") - pass - -###################################################################################################################\ -class QA_GUI_DateFetch_SU_job01_stock_year(QA_GUI_Date_Fetch_Task): - # todo fix here 不会执行 __init__的 QThread 是一个很特别的对象。 - # def __int__(self): - # # # 初始化函数,默认 - # super(QA_GUI_DateFetch_SU_job01_stock_year, self).__init__() - - def startTaskTriggerHandler(self, info_str): - self.changeRunningTaskColor0(QtCore.Qt.magenta) - pass - - def doneTaskTriggerHandler(self, info_str): - # - self.changeRunningTaskColor0(QtCore.Qt.green) - pass - - def updateProgressTriggerHandler(self, progress): - # print('update task progress ', progress); - self.qProgressBar.setValue(progress) - pass - - def updateLogTriggerHandler(self, log): - # print("append task log emite triggered!", log); - # self.logDisplay.append(log) - if log and log.strip(): - rowCount = self.logDisplay.rowCount() - newItem1 = QTableWidgetItem(log) - newItem2 = QTableWidgetItem("QA_SU_save_stock_year") - self.logDisplay.setRowCount(rowCount + 1) - self.logDisplay.setItem(rowCount, 0, newItem1) - self.logDisplay.setItem(rowCount, 1, newItem2) - #self.logDisplay.scrollToBottom() - - pass - - def run(self): - self.trigger_start_task_begin.emit("begin") - QA_SU_save_stock_year(client=DATABASE, ui_log= self.trigger_new_log, ui_progress= self.trigger_new_progress) - self.trigger_start_task_done.emit("end") - - pass -###################################################################################################################\ -class QA_GUI_DateFetch_SU_job02_stock_xdxr(QA_GUI_Date_Fetch_Task): - # todo fix here 不会执行 __init__的 QThread 是一个很特别的对象。 - # def _init_(self): - # # 初始化函数,默认 - # super(QA_GUI_DateFetch_SU_job02_stock_xdxr, self).__init__() - - def startTaskTriggerHandler(self, info_str): - self.changeRunningTaskColor0(QtCore.Qt.red) - pass - - def doneTaskTriggerHandler(self, info_str): - # - self.changeRunningTaskColor0(QtCore.Qt.green) - pass - - def updateProgressTriggerHandler(self, progress): - # print('update task progress ', progress); - self.qProgressBar.setValue(progress) - pass - - def updateLogTriggerHandler(self, log): - # print("append task log emite triggered!", log); - # self.logDisplay.append(log) - if log and log.strip(): - rowCount = self.logDisplay.rowCount() - newItem1 = QTableWidgetItem(log) - newItem2 = QTableWidgetItem("QA_SU_save_stock_xdxr") - self.logDisplay.setRowCount(rowCount + 1) - self.logDisplay.setItem(rowCount, 0, newItem1) - self.logDisplay.setItem(rowCount, 1, newItem2) - #self.logDisplay.scrollToBottom() - pass - - - def run(self): - self.trigger_start_task_begin.emit("begin") - QA_SU_save_stock_xdxr(client=DATABASE, ui_log= self.trigger_new_log, ui_progress= self.trigger_new_progress) - self.trigger_start_task_done.emit("end") - pass - -###################################################################################################################\ - -class QA_GUI_DateFetch_SU_job03_stock_min(QA_GUI_Date_Fetch_Task): - def startTaskTriggerHandler(self, info_str): - self.changeRunningTaskColor0(QtCore.Qt.red) - pass - - def doneTaskTriggerHandler(self, info_str): - # - self.changeRunningTaskColor0(QtCore.Qt.green) - pass - - def updateProgressTriggerHandler(self, progress): - # print('update task progress ', progress); - self.qProgressBar.setValue(progress) - pass - - def updateLogTriggerHandler(self, log): - # print("append task log emite triggered!", log); - # self.logDisplay.append(log) - if log and log.strip(): - rowCount = self.logDisplay.rowCount() - newItem1 = QTableWidgetItem(log) - newItem2 = QTableWidgetItem("QA_SU_save_stock_min") - self.logDisplay.setRowCount(rowCount + 1) - self.logDisplay.setItem(rowCount, 0, newItem1) - self.logDisplay.setItem(rowCount, 1, newItem2) - #self.logDisplay.scrollToBottom() - pass - - def run(self): - self.trigger_start_task_begin.emit("begin") - QA_SU_save_stock_min(client=DATABASE, ui_log= self.trigger_new_log, ui_progress= self.trigger_new_progress) - self.trigger_start_task_done.emit("end") - pass -################################################################################################################### - -class QA_GUI_DateFetch_SU_job04_index_day(QA_GUI_Date_Fetch_Task): - def startTaskTriggerHandler(self, info_str): - self.changeRunningTaskColor0(QtCore.Qt.red) - pass - - def doneTaskTriggerHandler(self, info_str): - # - self.changeRunningTaskColor0(QtCore.Qt.green) - pass - - def updateProgressTriggerHandler(self, progress): - # print('update task progress ', progress); - self.qProgressBar.setValue(progress) - pass - - def updateLogTriggerHandler(self, log): - # print("append task log emite triggered!", log); - # self.logDisplay.append(log) - if log and log.strip(): - rowCount = self.logDisplay.rowCount() - newItem1 = QTableWidgetItem(log) - newItem2 = QTableWidgetItem("QA_SU_save_index_day") - self.logDisplay.setRowCount(rowCount + 1) - self.logDisplay.setItem(rowCount, 0, newItem1) - self.logDisplay.setItem(rowCount, 1, newItem2) - # self.logDisplay.scrollToBottom() - pass - - def run(self): - self.trigger_start_task_begin.emit("begin") - QA_SU_save_index_day(client=DATABASE, ui_log=self.trigger_new_log, ui_progress=self.trigger_new_progress) - self.trigger_start_task_done.emit("end") - pass - -################################################################################################################### - -class QA_GUI_DateFetch_SU_job05_index_min(QA_GUI_Date_Fetch_Task): - def startTaskTriggerHandler(self, info_str): - self.changeRunningTaskColor0(QtCore.Qt.red) - pass - - def doneTaskTriggerHandler(self, info_str): - # - self.changeRunningTaskColor0(QtCore.Qt.green) - pass - - def updateProgressTriggerHandler(self, progress): - # print('update task progress ', progress); - self.qProgressBar.setValue(progress) - pass - - def updateLogTriggerHandler(self, log): - # print("append task log emite triggered!", log); - # self.logDisplay.append(log) - if log and log.strip(): - rowCount = self.logDisplay.rowCount() - newItem1 = QTableWidgetItem(log) - newItem2 = QTableWidgetItem("QA_SU_save_index_min") - self.logDisplay.setRowCount(rowCount + 1) - self.logDisplay.setItem(rowCount, 0, newItem1) - self.logDisplay.setItem(rowCount, 1, newItem2) - # self.logDisplay.scrollToBottom() - pass - - def run(self): - self.trigger_start_task_begin.emit("begin") - QA_SU_save_index_min(client=DATABASE, ui_log=self.trigger_new_log, ui_progress=self.trigger_new_progress) - self.trigger_start_task_done.emit("end") - pass - -################################################################################################################### - -class QA_GUI_DateFetch_SU_job06_etf_day(QA_GUI_Date_Fetch_Task): - def startTaskTriggerHandler(self, info_str): - self.changeRunningTaskColor0(QtCore.Qt.red) - pass - - def doneTaskTriggerHandler(self, info_str): - # - self.changeRunningTaskColor0(QtCore.Qt.green) - pass - - def updateProgressTriggerHandler(self, progress): - # print('update task progress ', progress); - self.qProgressBar.setValue(progress) - pass - - def updateLogTriggerHandler(self, log): - # print("append task log emite triggered!", log); - # self.logDisplay.append(log) - if log and log.strip(): - rowCount = self.logDisplay.rowCount() - newItem1 = QTableWidgetItem(log) - newItem2 = QTableWidgetItem("QA_SU_save_etf_day") - self.logDisplay.setRowCount(rowCount + 1) - self.logDisplay.setItem(rowCount, 0, newItem1) - self.logDisplay.setItem(rowCount, 1, newItem2) - # self.logDisplay.scrollToBottom() - pass - - def run(self): - self.trigger_start_task_begin.emit("begin") - QA_SU_save_etf_day(client=DATABASE, ui_log=self.trigger_new_log, ui_progress=self.trigger_new_progress) - self.trigger_start_task_done.emit("end") - pass - -################################################################################################################### -class QA_GUI_DateFetch_SU_job07_etf_min(QA_GUI_Date_Fetch_Task): - def startTaskTriggerHandler(self, info_str): - self.changeRunningTaskColor0(QtCore.Qt.red) - pass - - def doneTaskTriggerHandler(self, info_str): - # - self.changeRunningTaskColor0(QtCore.Qt.green) - pass - - def updateProgressTriggerHandler(self, progress): - # print('update task progress ', progress); - self.qProgressBar.setValue(progress) - pass - - def updateLogTriggerHandler(self, log): - # print("append task log emite triggered!", log); - # self.logDisplay.append(log) - if log and log.strip(): - rowCount = self.logDisplay.rowCount() - newItem1 = QTableWidgetItem(log) - newItem2 = QTableWidgetItem("QA_SU_save_etf_min") - self.logDisplay.setRowCount(rowCount + 1) - self.logDisplay.setItem(rowCount, 0, newItem1) - self.logDisplay.setItem(rowCount, 1, newItem2) - # self.logDisplay.scrollToBottom() - pass - - def run(self): - self.trigger_start_task_begin.emit("begin") - QA_SU_save_etf_min(client=DATABASE, ui_log=self.trigger_new_log, ui_progress=self.trigger_new_progress) - self.trigger_start_task_done.emit("end") - pass - -################################################################################################################### -class QA_GUI_DateFetch_SU_job08_stock_list(QA_GUI_Date_Fetch_Task): - def startTaskTriggerHandler(self, info_str): - self.changeRunningTaskColor0(QtCore.Qt.red) - pass - - def doneTaskTriggerHandler(self, info_str): - # - self.changeRunningTaskColor0(QtCore.Qt.green) - pass - - def updateProgressTriggerHandler(self, progress): - # print('update task progress ', progress); - self.qProgressBar.setValue(progress) - pass - - def updateLogTriggerHandler(self, log): - # print("append task log emite triggered!", log); - # self.logDisplay.append(log) - if log and log.strip(): - rowCount = self.logDisplay.rowCount() - newItem1 = QTableWidgetItem(log) - newItem2 = QTableWidgetItem("QA_SU_save_stock_list") - self.logDisplay.setRowCount(rowCount + 1) - self.logDisplay.setItem(rowCount, 0, newItem1) - self.logDisplay.setItem(rowCount, 1, newItem2) - # self.logDisplay.scrollToBottom() - pass - - def run(self): - self.trigger_start_task_begin.emit("begin") - QA_SU_save_stock_list(client=DATABASE, ui_log=self.trigger_new_log, ui_progress=self.trigger_new_progress) - self.trigger_start_task_done.emit("end") - pass - - - -class QA_GUI_DateFetch_SU_job09_stock_block(QA_GUI_Date_Fetch_Task): - def startTaskTriggerHandler(self, info_str): - self.changeRunningTaskColor0(QtCore.Qt.red) - pass - - def doneTaskTriggerHandler(self, info_str): - # - self.changeRunningTaskColor0(QtCore.Qt.green) - pass - - def updateProgressTriggerHandler(self, progress): - # print('update task progress ', progress); - self.qProgressBar.setValue(progress) - pass - - def updateLogTriggerHandler(self, log): - # print("append task log emite triggered!", log); - # self.logDisplay.append(log) - if log and log.strip(): - rowCount = self.logDisplay.rowCount() - newItem1 = QTableWidgetItem(log) - newItem2 = QTableWidgetItem("QA_SU_save_stock_list") - self.logDisplay.setRowCount(rowCount + 1) - self.logDisplay.setItem(rowCount, 0, newItem1) - self.logDisplay.setItem(rowCount, 1, newItem2) - # self.logDisplay.scrollToBottom() - pass - - def run(self): - self.trigger_start_task_begin.emit("begin") - QA_SU_save_stock_block(client=DATABASE, ui_log=self.trigger_new_log, ui_progress=self.trigger_new_progress) - self.trigger_start_task_done.emit("end") - pass - -class QA_GUI_DateFetch_SU_job10_stock_info(QA_GUI_Date_Fetch_Task): - def startTaskTriggerHandler(self, info_str): - self.changeRunningTaskColor0(QtCore.Qt.red) - pass - - def doneTaskTriggerHandler(self, info_str): - # - self.changeRunningTaskColor0(QtCore.Qt.green) - pass - - def updateProgressTriggerHandler(self, progress): - # print('update task progress ', progress); - self.qProgressBar.setValue(progress) - pass - - def updateLogTriggerHandler(self, log): - # print("append task log emite triggered!", log); - # self.logDisplay.append(log) - if log and log.strip(): - rowCount = self.logDisplay.rowCount() - newItem1 = QTableWidgetItem(log) - newItem2 = QTableWidgetItem("QA_SU_save_stock_list") - self.logDisplay.setRowCount(rowCount + 1) - self.logDisplay.setItem(rowCount, 0, newItem1) - self.logDisplay.setItem(rowCount, 1, newItem2) - # self.logDisplay.scrollToBottom() - pass - - def run(self): - self.trigger_start_task_begin.emit("begin") - QA_SU_save_stock_info(client=DATABASE, ui_log=self.trigger_new_log, ui_progress=self.trigger_new_progress) - self.trigger_start_task_done.emit("end") - pass - - -class QA_GUI_DateFetch_SU_job11_stock_transaction(QA_GUI_Date_Fetch_Task): - def startTaskTriggerHandler(self, info_str): - self.changeRunningTaskColor0(QtCore.Qt.red) - pass - - def doneTaskTriggerHandler(self, info_str): - # - self.changeRunningTaskColor0(QtCore.Qt.green) - pass - - def updateProgressTriggerHandler(self, progress): - # print('update task progress ', progress); - self.qProgressBar.setValue(progress) - pass - - def updateLogTriggerHandler(self, log): - # print("append task log emite triggered!", log); - # self.logDisplay.append(log) - if log and log.strip(): - rowCount = self.logDisplay.rowCount() - newItem1 = QTableWidgetItem(log) - newItem2 = QTableWidgetItem("QA_SU_save_stock_transaction") - self.logDisplay.setRowCount(rowCount + 1) - self.logDisplay.setItem(rowCount, 0, newItem1) - self.logDisplay.setItem(rowCount, 1, newItem2) - # self.logDisplay.scrollToBottom() - pass - - def run(self): - self.trigger_start_task_begin.emit("begin") - QA_SU_save_stock_transaction(client=DATABASE, ui_log=self.trigger_new_log, ui_progress=self.trigger_new_progress) - self.trigger_start_task_done.emit("end") - pass - - - -class QA_GUI_DateFetch_SU_job12_option_day(QA_GUI_Date_Fetch_Task): - def startTaskTriggerHandler(self, info_str): - self.changeRunningTaskColor0(QtCore.Qt.red) - pass - - def doneTaskTriggerHandler(self, info_str): - # - self.changeRunningTaskColor0(QtCore.Qt.green) - pass - - def updateProgressTriggerHandler(self, progress): - # print('update task progress ', progress); - self.qProgressBar.setValue(progress) - pass - - def updateLogTriggerHandler(self, log): - # print("append task log emite triggered!", log); - # self.logDisplay.append(log) - if log and log.strip(): - rowCount = self.logDisplay.rowCount() - newItem1 = QTableWidgetItem(log) - newItem2 = QTableWidgetItem("QA_SU_save_stock_transaction") - self.logDisplay.setRowCount(rowCount + 1) - self.logDisplay.setItem(rowCount, 0, newItem1) - self.logDisplay.setItem(rowCount, 1, newItem2) - # self.logDisplay.scrollToBottom() - pass - - def run(self): - self.trigger_start_task_begin.emit("begin") - QA_SU_save_option_day(client=DATABASE, ui_log=self.trigger_new_log, ui_progress=self.trigger_new_progress) - self.trigger_start_task_done.emit("end") - pass - -#通达信pytdx 会输出消息, 一同输出到gui界面只能够 -class EmittingStream(QtCore.QObject): - textWritten = QtCore.pyqtSignal(str) # 定义一个发送str的信号 - - def write(self, text): - self.textWritten.emit(str(text)) - - - -class QA_GUI_Selected_TaskQueue(QThread): - - # QThread 继承的不执行__init__ - #def __int__(self, logDisplay): - # 奇怪的问题, 不执行 __init__ - # 初始化函数,默认 - # super().__init__() - #sfassda - #print("run here") - #exit(0) - #self.logDisplay = logDisplay - #sys.stderr.textWritten.connect(self.outputWrittenStderr) - - - - # 下面将print 系统输出重定向到textEdit中 - #sys.stdout = EmittingStream() - #sys.stderr = EmittingStream() - - - # 接收信号str的信号槽 - ''' - def outputWrittenStdout(self, text): - cursor = self.logDisplay.textCursor() - cursor.movePosition(QtGui.QTextCursor.End) - cursor.insertText(text) - self.logDisplay.setTextCursor(cursor) - self.logDisplay.ensureCursorVisible() - - def outputWrittenStderr(self, text): - cursor = self.logDisplay.textCursor() - cursor.movePosition(QtGui.QTextCursor.End) - cursor.insertText(text) - self.logDisplay.setTextCursor(cursor) - self.logDisplay.ensureCursorVisible() - ''' - - - - # 定义一个信号, - trigger_all_task_start = pyqtSignal(str) - trigger_all_task_done = pyqtSignal(str) - - #定义任务(每个是一个线程) - QA_GUI_Task_List = [] - def run(self): - - self.trigger_all_task_start.emit('all_task_start') - - for iSubTask in self.QA_GUI_Task_List: - iSubTask.start() - # wait finish iSubTask - while (iSubTask.isRunning()): - time.sleep(1) - - self.trigger_all_task_done.emit('all_task_done') - - def putTask(self, subTask): - self.QA_GUI_Task_List.append(subTask) - - def clearTask(self): - self.QA_GUI_Task_List.clear() \ No newline at end of file diff --git a/QUANTAXIS_Monitor_GUI/TasksByThreading/QThread_CheckStockBlock_DB_Task.py b/QUANTAXIS_Monitor_GUI/TasksByThreading/QThread_CheckStockBlock_DB_Task.py deleted file mode 100644 index b36bfa480..000000000 --- a/QUANTAXIS_Monitor_GUI/TasksByThreading/QThread_CheckStockBlock_DB_Task.py +++ /dev/null @@ -1,169 +0,0 @@ -import time - - - -from PyQt5.QtCore import * -from PyQt5.QtGui import * -from PyQt5.QtWidgets import * -from PyQt5 import QtCore - -from QUANTAXIS.QAFetch.QAQuery import QA_fetch_stock_list -from QUANTAXIS.QAUtil import DATABASE - - -from QUANTAXIS.QAUtil import (DATABASE,QA_Setting, QA_util_date_stamp, - QA_util_date_valid, QA_util_dict_remove_key, - QA_util_log_info, QA_util_code_tolist, QA_util_date_str2int, QA_util_date_int2str, - QA_util_sql_mongo_sort_DESCENDING, - QA_util_time_stamp, QA_util_to_json_from_pandas, - trade_date_sse, QADate_trade,QADate) - - -from QUANTAXIS.QAUtil.QADate_trade import * -from QUANTAXIS.QAUtil.QADate import * - -from QUANTAXIS.QAFetch.QAQuery import * -from QUANTAXIS.QAFetch.QAQuery_Advance import * -from QUANTAXIS.QAUtil.QADate_trade import * - -import pandas as pd -import numpy as np - -from QUANTAXIS_Monitor_GUI.TasksByThreading.QThread_RootClass import * -import time - - -class QThread_Check_StockBlock_DB(QThread_RootClass): - - def QA_statistic_block_data(self): - - # 🛠 todo 直接使用monogodb 数据库去统计 - try: - block_list_df = QA_fetch_stock_block() - blockNameList = {} - block_list_df = block_list_df.set_index(['blockname']) - - for strIndexBlockName in block_list_df.index: - try: - dict = blockNameList[strIndexBlockName] - dict['count'] = dict['count'] + 1 - self.strTaskRunningLog = "正在统计板块{} 股票个数{}".format(strIndexBlockName, dict['count']) - - except Exception as ee: - dictNew = {} - dictNew['up'] = 0 #上涨家数 - dictNew['even'] = 0 #平盘家数 - dictNew['down'] = 0 #下跌家数 - dictNew['count'] = 0 #板块股票数 - dictNew['upRatio'] = 0.0 #上涨家数比率 - dictNew['downRation'] = 0.0 #下跌家数比率 - blockNameList[strIndexBlockName] = dictNew - #row2 = block_list_df[i] - ####################################################################################################### - - strToday = QADate.QA_util_today_str() - strEndDate = QADate_trade.QA_util_get_real_date(date = strToday) - strStartDate = QADate_trade.QA_util_get_last_day(date= strEndDate) - - codeTwoDayPriceeDict = {} - stock_list = QA_fetch_stock_list() - - stock_list_len = len(stock_list) - stock_name_count = 0 - for aStockCode in stock_list: - stock_name_count = stock_name_count + 1 - strAcode = aStockCode['code'] - strAName = aStockCode['name'] - priceTowDay = QA_fetch_stock_day_adv(code=strAcode, start=strStartDate, end=strEndDate) - - up = None - if priceTowDay is not None: - priceTowDay.to_qfq() - # price_len = len(priceTowDay) - # print(priceTowDay) - - price_len = len(priceTowDay) - if price_len == 2: - closeSerial = priceTowDay.close - # todayPrice = priceTowDay[1].close - v1 = closeSerial[0] - v2 = closeSerial[1] - if v1 < v2: - up = True - else: - up = False - - codeTwoDayPriceeDict[strAcode] = {'pricetwoday':priceTowDay, - 'up':up} - - if codeTwoDayPriceeDict[strAcode]['up'] is not None and codeTwoDayPriceeDict[strAcode]['up'] == True: - self.strTaskRunningLog = "正在获取股票价格 {} {} 上涨 ⬆🔺, 进度{}/{} " \ - .format(strAcode, strAName, stock_name_count, stock_list_len) - - elif codeTwoDayPriceeDict[strAcode]['up'] is not None and codeTwoDayPriceeDict[strAcode]['up'] == False: - self.strTaskRunningLog = "正在获取股票价格 {} {} 下跌 ⬇️, 进度{}/{} " \ - .format(strAcode, strAName, stock_name_count, stock_list_len) - - else: - self.strTaskRunningLog = "正在获取股票价格 {} {} 和前一天的无法统计️, 进度{}/{} " \ - .format(strAcode, strAName, stock_name_count, stock_list_len) - ########################################################################################################## - - - - len_block_size = len(blockNameList) - count = 0 - for blockName in blockNameList.keys(): - count = count + 1 - stocks_in_block = QA_fetch_stock_block_adv(code=None, blockname= blockName) - self.strTaskRunningLog = "正在统计板块{} ,进度{}/{}".format(blockName,count,len_block_size) - code_list = stocks_in_block.code - - iCodeLength = len(code_list) - iCountForCode = 0 - - for iCode in code_list: - - iCountForCode = iCountForCode + 1 - - try: - priceTowDay = codeTwoDayPriceeDict[iCode]['pricetwoday'] - upValue = codeTwoDayPriceeDict[iCode]['up'] - - if priceTowDay is not None: - if upValue == True: - blockNameList[blockName]['up'] = blockNameList[blockName]['up'] + 1 - elif upValue == False: - blockNameList[blockName]['down'] = blockNameList[blockName]['down'] + 1 - - - except Exception as ee: - strErrorMsg = ee.__str__() - print(strErrorMsg) - - - - self.strTaskRunningLog = "正在统计板块{} ,进度{}/{} \n 股票 {}, 进度 {}/{}"\ - .format(blockName, count, len_block_size, iCode, iCountForCode, iCodeLength) - - pass - #print(stocks_in_block) - ####################################################################################################### - - except Exception as eee: - strErrorMsg = eee.__str__() - print(strErrorMsg) - - finally: - return blockNameList - - - # 给 Table View 使用 - blockStatisticList = {} - ########################################################################################################## - def run(self): - #统计板块涨跌幅 - self.strTaskRunningLog = "开始统计板块涨跌幅数据" - self.blockStatisticList = self.QA_statistic_block_data() - self.strTaskRunningResult = "完成统计板块涨跌幅数据" - pass \ No newline at end of file diff --git a/QUANTAXIS_Monitor_GUI/TasksByThreading/QThread_CheckZJLX_DB_Task.py b/QUANTAXIS_Monitor_GUI/TasksByThreading/QThread_CheckZJLX_DB_Task.py deleted file mode 100644 index c0ee786a2..000000000 --- a/QUANTAXIS_Monitor_GUI/TasksByThreading/QThread_CheckZJLX_DB_Task.py +++ /dev/null @@ -1,295 +0,0 @@ - -import time - - - -from PyQt5.QtCore import * -from PyQt5.QtGui import * -from PyQt5.QtWidgets import * -from PyQt5 import QtCore - -from QUANTAXIS.QAFetch.QAQuery import QA_fetch_stock_list -from QUANTAXIS.QAUtil import DATABASE - - -from QUANTAXIS.QAUtil import (DATABASE,QA_Setting, QA_util_date_stamp, - QA_util_date_valid, QA_util_dict_remove_key, - QA_util_log_info, QA_util_code_tolist, QA_util_date_str2int, QA_util_date_int2str, - QA_util_sql_mongo_sort_DESCENDING, - QA_util_time_stamp, QA_util_to_json_from_pandas, - trade_date_sse, QADate_trade,QADate) - - -from QUANTAXIS.QAFetch.QAQuery import QA_fetch_stock_list -from QUANTAXIS.QAUtil.QADate_trade import * - -import pandas as pd -import numpy as np - -from QUANTAXIS_Monitor_GUI.TasksByThreading.QThread_RootClass import * - - -class QThread_Check_ZJLX_DB_Status(QThread_RootClass): - - - #db.getCollection('eastmoney_stock_zjlx').find({ 'stock_code':{'$in': ['000001']}}).sort({date:1}) - - ''' - > db.eastmoney_stock_zjlx.aggregate([{$sort:{stock_code:1, date:1}},{$group: {_id:'$stock_code', first_date:{$first:'$date'}, last_date:{$last:'$date'}, total_num:{$sum : 1}}}]) - - ''' - def QA_count_eastmoney_stock_xjlc_record_count_by_aggregate(self, collections=DATABASE.eastmoney_stock_zjlx): - #codeArrayList = QA_util_code_tolist(str_stock_code_list) - - sort = {'$sort':{'stock_code':1, 'date':1}} #按照count对应的值得降序排序 - group = {'$group': {'_id': '$stock_code', 'first_date':{ '$first':'$date'}, 'last_date':{'$last':'$date'}, 'total_num':{'$sum' : 1} }} - pipeline = [group, sort] - - cursor = collections.aggregate( - [ - {'$sort':{'stock_code':1, 'date':1}}, - {'$group':{'_id': '$stock_code', 'first_date':{ '$first':'$date'}, 'last_date':{'$last':'$date'}, 'total_num':{'$sum' : 1}}} - ] - ) - items = [item for item in cursor] - - def takeId_sort(elem): - return elem['_id'] - items.sort(key=takeId_sort) - - #停牌的股票,过滤 - strToday = QADate.QA_util_today_str() - strLastTradeDate = QADate_trade.QA_util_get_real_date(strToday) - strLastTradeDate = QADate_trade.QA_util_get_last_day(strLastTradeDate) #网页版资金流向只更新到前一天 - - #比较日期 - - yesterTradeDayInt = QADate.QA_util_date_str2int(strLastTradeDate) - - for item in items: - lastDayIntInDB = QADate.QA_util_date_str2int(item['last_date']) - if lastDayIntInDB < yesterTradeDayInt: - item['need_update'] = 'Yes' - else: - item['need_update'] = 'No' - - #map( lambda aRecDict: aRecDict['need_update'] = (aRecDict['last_date'] == strLastTradeDate) , items) - # - #map( lambda aRecDict: (aRecDict['need_update'] = (aRecDict['last_date'] == strLastTradeDate)) , items) - - return items - - - # 非常慢 - def QA_count_eastmoney_stock_xjlc_record_count_one_by_one(self, str_stock_code, collections=DATABASE.eastmoney_stock_zjlx): - - codeArray = QA_util_code_tolist(str_stock_code) - cursor = collections.find({ - 'stock_code': {'$in': codeArray} - }).sort('date') - - sizeRec = cursor.count() - - firstRec = None - lastRec = None - if sizeRec > 0: - firstRec = cursor[0] - lastRec = cursor[sizeRec-1] - - #返回 【code 记录条数 开始日期 结束日期 】 - #print(firstRec) - #print(lastRec) - - firstRecDate = None - if firstRec is not None: - firstRecDate = firstRec['date'] - - lastRecDate = None - if lastRec is not None: - lastRecDate = lastRec['date'] - - - return [str_stock_code, sizeRec ,firstRecDate, lastRecDate] - - # 按照 QUANTAXIS 的风格去 写 2333333333 - # todo 移动到 QUANTAXIS 目录中去, 给命令行调用 - # - def QA_fetch_eastmoney_stock_zjlx(self,str_stock_code = None, strStartDate = None, strEndDate = None, strFormat='numpy',collections=DATABASE.eastmoney_stock_zjlx): - - codeArray = QA_util_code_tolist(str_stock_code) - if QA_util_date_valid(strEndDate): - - if strStartDate == None and strEndDate == None: - - cursor = collections.find({ - 'stock_code': {'$in': codeArray} - }) - - items = [item for item in cursor] - res = pd.DataFrame(items) - - #todo fixhere reset pandas index - - if format in ['P', 'p', 'pandas', 'pd']: - return res - elif format in ['json', 'dict']: - return QA_util_to_json_from_pandas(res) - # 多种数据格式 - elif format in ['n', 'N', 'numpy']: - return np.asarray(res) - elif format in ['list', 'l', 'L']: - return np.asarray(res).tolist() - else: - print( - "QA Error QA_fetch_stock_day format parameter %s is none of \"P, p, pandas, pd , json, dict , n, N, numpy, list, l, L, !\" " % format) - return None - else: - cursor2 = collections.find({ - 'stock_code': { '$in': codeArray }, - 'date': { - '$lte': strEndDate, - '$gte': strStartDate - } - }); - - items = [item for item in cursor2] - res = pd.DataFrame(items) - - # todo fixhere reset pandas index - - if format in ['P', 'p', 'pandas', 'pd']: - return res - elif format in ['json', 'dict']: - return QA_util_to_json_from_pandas(res) - # 多种数据格式 - elif format in ['n', 'N', 'numpy']: - return np.asarray(res) - elif format in ['list', 'l', 'L']: - return np.asarray(res).tolist() - else: - print( - "QA Error QA_fetch_stock_day format parameter %s is none of \"P, p, pandas, pd , json, dict , n, N, numpy, list, l, L, !\" " % format) - return None - # - # sizeRec = cursor2.count() - # firstRec = cursor2[0] - # lastRec = cursor2[sizeRec-1] - # allItems2 = [item for item in cursor2] - # print(allItems2) - pass - - - ########################################################################################################## - - ''' - emit the string to the UI log table - ''' - pyqtSignalToLogTable = None - ''' - [股票代码, 记录数 , 开始日期, 结束日期, 是否需要获取] - ''' - zjlxRecNeedUpdateStockCodes = [] - ''' - 全部股票列表 - ''' - stockListAll = [] - - #################################################################################################### - - - - #################################################################################################### - def run(self): - - # - def find(f, seq): - """Return first item in sequence where f(item) == True.""" - for item in seq: - if f(item): - return item - - self.zjlxRecNeedUpdateStockCodes.clear(); - self.stockListAll.clear() - self.stockListAll = QA_fetch_stock_list() - - self.strTaskRunningLog = '正在检查数据库,已经获取的数据' - itemsInZJLX = self.QA_count_eastmoney_stock_xjlc_record_count_by_aggregate() - - ''' - 追究没有获取过的记录, - ''' - - # 非常慢 - # codeNeedAppend = [] - # for aItemInAllStock in self.stockListAll: - # code0 = aItemInAllStock['code'] - # #self.strTaskRunningLog = '正在检查数据 {}'.format(code0) - # - # foundItem = find(lambda aRec: aRec['_id'] == code0, itemsInZJLX) - # if foundItem is None: - # codeNeedAppend.append(code0) - # - # - # print(codeNeedAppend) - - # 使用 dict - allItemsByDict = {} - partItemsByDict = {} - - needToAppendCode = [] - - self.strTaskRunningLog = '正在检查数据库,从未获取的记录' - - for iRecWhole in self.stockListAll: - allItemsByDict[iRecWhole['code']] = iRecWhole['code'] - - for iRecPart in itemsInZJLX: - partItemsByDict[iRecPart['_id']] = iRecPart['_id'] - - for iRec in allItemsByDict: - try: - stock_code = partItemsByDict[iRec] - except Exception as ee: - #part 里面 没有 这个股票代码 - needToAppendCode.append(iRec) - #print(ee) - - #print(needToAppendCode) - - for codeAppend in needToAppendCode: - anItem = {'_id': codeAppend, 'first_date': '第一次获取', 'last_date': '第一次获取', 'total_num': 0, 'need_update': 'Yes'} - itemsInZJLX.append(anItem) - - def takeCode(elem): - return elem['_id'] - - itemsInZJLX.sort(key=takeCode) - - - iIndexZJLX = 0 - zjlxCount = len(itemsInZJLX) - - for itemInZjlx in itemsInZJLX: - try: - iIndexZJLX = iIndexZJLX + 1 - self.strTaskRunningLog = '正在检查数据:{} 进度:{}/{}'.format(itemInZjlx, iIndexZJLX, zjlxCount) - - # item['_id'], item['start_date'], item['end_date'], item['total_num'], item['need_update'] - col0 = itemInZjlx['_id'] - col1 = itemInZjlx['first_date'] - col2 = itemInZjlx['last_date'] - col3 = itemInZjlx['total_num'] - col4 = itemInZjlx['need_update'] - self.pyqtSignalToLogTable.emit(col0, col1, col2, col3, col4) - - if itemInZjlx['need_update'] == 'Yes': - self.zjlxRecNeedUpdateStockCodes.append(col0) - - - except Exception as ee: - print(ee) - - - - self.strTaskRunningResult = " 任务结束 " - pass \ No newline at end of file diff --git a/QUANTAXIS_Monitor_GUI/TasksByThreading/QThread_FetchWebPage.py b/QUANTAXIS_Monitor_GUI/TasksByThreading/QThread_FetchWebPage.py deleted file mode 100644 index 5f61cd81e..000000000 --- a/QUANTAXIS_Monitor_GUI/TasksByThreading/QThread_FetchWebPage.py +++ /dev/null @@ -1,752 +0,0 @@ - -import time -import datetime -import socket - -from PyQt5.QtCore import * -from PyQt5.QtGui import * -from PyQt5.QtWidgets import * -from PyQt5 import QtCore - -from QUANTAXIS.QAFetch.QAQuery import QA_fetch_stock_list -from QUANTAXIS.QAUtil import DATABASE - - -from QUANTAXIS.QAUtil import (DATABASE,QA_Setting, QA_util_date_stamp, - QA_util_date_valid, QA_util_dict_remove_key, - QA_util_log_info, QA_util_code_tolist, QA_util_date_str2int, QA_util_date_int2str, - QA_util_sql_mongo_sort_DESCENDING, - QA_util_time_stamp, QA_util_to_json_from_pandas, - trade_date_sse, QADate_trade,QADate) - - -from QUANTAXIS.QAFetch.QAQuery import QA_fetch_stock_list -from QUANTAXIS.QAUtil.QADate_trade import * - -import pandas as pd -import numpy as np - -from QUANTAXIS_Monitor_GUI.TasksByThreading.QThread_RootClass import * - - -class QThread_Fetch_Eastmoney_WebPageData(QThread_RootClass): - - lastTimeCheckPointStart = 0 - stockCodeList = [] - - #每次修改数据库记录更新时间戳, 防止线程没有反应, 为实现??? - lastTimeThreadActivateTimeStamp = datetime.datetime.now() - - connectAddress = "" - connectPortInt = 0 - processIndex = -1 - - ''' - emit the string to the UI log table - ''' - pyqtSignalToLogOpInfoTable = None - pyqtSignalToLogErrorTable = None - - chrome_start_ok = False - bThreadTobeOver = False - - def send_msg_to_server(self, sock, strMsg0): - bytes_content = strMsg0.encode() - bytes_content = bytes_content.zfill(128) - assert (len(bytes_content) == 128) - # 🛠todo fix 128 个byte 很傻 - sock.sendall(bytes_content) - - def unpack_cmd_string(self, data): - cmdString = data.decode(); - cmdArry = cmdString.split('@') - cmdArry[0] = cmdArry[0].strip('0') - return cmdArry - - def get_connect_sock(self): - sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - server_address = (self.connectAddress, self.connectPortInt) - sock.connect(server_address) - return sock - - - - def run(self): - - try: - sock = self.get_connect_sock() - strMsg0 = "start_chrome_driver@start_chrome_driver" - self.send_msg_to_server(sock, strMsg0) - - data = sock.recv(128) - if len(data) == 128: - cmd = self.unpack_cmd_string(data) - if (cmd[0] == 'state' and cmd[1] == 'start_chrome_driver_ok'): - chrome_start_ok = True - - strProcessIndex = str(self.processIndex) - strCode = "None" - strOp = "✅启动ChromeDriver程序✅" - strInfo = "OK"; - self.pyqtSignalToLogOpInfoTable.emit(strProcessIndex, strCode, strOp, strInfo) - - elif (cmd == 'state'): - errorMessage = cmd[2] - strProcessIndex = str(self.processIndex) - strCode = "None" - strOp = "❌启动ChromeDriver程序失败1❌" - strErroInfo = errorMessage; - self.pyqtSignalToLogErrorTable.emit(strProcessIndex, strCode, strOp, strErroInfo) - - sock.close() - ############################################################# - ############################################################# - # 循环获取股票列表,获取一个股,连接一次,然后 释放连接 - for iCodeIndex in range(self.lastTimeCheckPointStart, len(self.stockCodeList)): - - # 进程收到关闭请求 - if self.bThreadTobeOver == True: - strProcessIndex = str(self.processIndex) - strCode = "None" - strOp = "✅收到退出线程停止命令✅" - strInfo = "OK"; - self.pyqtSignalToLogOpInfoTable.emit(strProcessIndex, strCode, strOp, strInfo) - break; - - - strProcessIndex = str(self.processIndex) - strCode = self.stockCodeList[iCodeIndex] - sock = self.get_connect_sock() - - ##send command - ############################################################# - strMsg0 = "fetch_a_stock_data_to_mongodb@%s" % strCode - self.send_msg_to_server(sock,strMsg0) - - data = sock.recv(128) - if len(data) == 128: - cmd = self.unpack_cmd_string(data) - if (cmd[0] == 'state' and cmd[1] == 'fetch_a_stock_data_to_mongodb_open_web_page_ok'): - strProcessIndex = str(self.processIndex) - strOp = "✅成功打开网页✅" - strInfo = "OK"; - self.pyqtSignalToLogOpInfoTable.emit(strProcessIndex, strCode, strOp, strInfo) - - - while True: - data = sock.recv(128) - if len(data) == 128: - cmd = self.unpack_cmd_string(data) - - if (cmd[0] == 'state' and cmd[1] == 'progress'): - prasePageProgress = cmd[2] - - strOp = "✅解析网页中🐞进度条报告" - strInfo = prasePageProgress; - self.pyqtSignalToLogOpInfoTable.emit(strProcessIndex, strCode, strOp, strInfo) - - ################################################################################### - # 进程收到关闭请求 - if self.bThreadTobeOver == True: - strProcessIndex = str(self.processIndex) - strCode = "None" - strOp = "✅收到退出线程停止命令✅" - strInfo = "OK"; - self.pyqtSignalToLogOpInfoTable.emit(strProcessIndex, strCode, strOp, strInfo) - break; - - continue - - elif (cmd[0] == 'state' and cmd[1] == 'hearbeat'): - prasePageDateStr = cmd[2] - - strOp = "✅解析网页中🕷进度日期报告" - strInfo = prasePageDateStr; - - self.pyqtSignalToLogOpInfoTable.emit(strProcessIndex, strCode, strOp, strInfo) - - ################################################################################### - # 进程收到关闭请求 - if self.bThreadTobeOver == True: - strProcessIndex = str(self.processIndex) - strCode = "None" - strOp = "✅收到退出线程停止命令✅" - strInfo = "OK"; - self.pyqtSignalToLogOpInfoTable.emit(strProcessIndex, strCode, strOp, strInfo) - break; - - continue - - elif (cmd[0] == 'state' and cmd[1] == 'fetch_a_stock_data_to_mongodb_prase_web_page_ok'): - successPraseWebPageRecord = cmd[2] - iRecNewCount = int(successPraseWebPageRecord) - strOp = "✅写入🐜数据库OK" - strInfo = "📋新增%d条记录" % iRecNewCount; - self.pyqtSignalToLogOpInfoTable.emit(strProcessIndex, strCode, strOp, strInfo) - break - - elif (cmd[0] == 'state' and cmd[1] == 'fetch_a_stock_data_to_mongodb_prase_web_page_failed'): - generalMessage = cmd[2] - strProcessIndex = str(self.processIndex) - strOp = "❌解析网页失败❌" - strErroInfo = generalMessage; - self.pyqtSignalToLogErrorTable.emit(strProcessIndex, strCode, strOp, strErroInfo) - break - else: - # 不应该执行到这里 - generalMessage = "" - if len(cmd)>=1 and cmd[0] is not None: - generalMessage = generalMessage + " " + cmd[0] - if len(cmd)>=2 and cmd[1] is not None: - generalMessage = generalMessage + " " + cmd[1] - if len(cmd)>=3 and cmd[2] is not None: - generalMessage = generalMessage + " " + cmd[2] - - strProcessIndex = str(self.processIndex) - strOp = "❌解析网页未知错误❌" - strErroInfo = generalMessage; - self.pyqtSignalToLogErrorTable.emit(strProcessIndex, strCode, strOp, strErroInfo) - - break - - elif (cmd[0] == 'state' and cmd[1] == 'fetch_a_stock_data_to_mongodb_open_web_page_failed'): - errorMessage = cmd[2] - strProcessIndex = str(self.processIndex) - strCode = strCode - strOp = "❌打开网页错误❌" - strErroInfo = errorMessage - self.pyqtSignalToLogErrorTable.emit(strProcessIndex, strCode, strOp, strErroInfo) - pass - - - sock.close() - - - ############################################################# - ############################################################# - sock = self.get_connect_sock() - strMsg0 = "shutdown_chrome_driver@shutdown_chrome_driver" - self.send_msg_to_server(sock,strMsg0) - - data = sock.recv(128) - if len(data) == 128: - cmd = self.unpack_cmd_string(data) - if( cmd[0] == 'state' and cmd[1] == 'shutdown_chrome_driver_ok'): - strProcessIndex = str(self.processIndex) - strCode = "None" - strOp = "✅关闭ChromeDriver程序✅" - strInfo = "OK"; - self.pyqtSignalToLogOpInfoTable.emit(strProcessIndex, strCode, strOp, strInfo) - elif (cmd[0] == 'state'): - errorMessage = cmd[1] - strProcessIndex = str(self.processIndex) - strCode = "None" - strOp = "❌关闭ChromeDriver程序失败1❌" - strErroInfo = errorMessage ; - self.pyqtSignalToLogErrorTable.emit(strProcessIndex, strCode, strOp, strErroInfo) - - - sock.close() - except Exception as ee: - errMsg = ee.__str__() - print(errMsg) - - finally: - pass - -''' - - def run33(self): - - ##send command - ############################################################# - strMsg0 = "start_chrome_driver@start_chrome_driver" - bytes_content = strMsg0.encode() - bytes_content = bytes_content.zfill(128) - assert (len(bytes_content) == 128) - # 🛠todo fix 128 个byte 很傻 - sock.sendall(bytes_content) - ############################################################# - ############################################################# - data = sock.recv(128) - if len(data) == 128: - cmdString = data.decode(); - cmdArry = cmdString.split('@') - cmd = cmdArry[0].strip('0') - parame = cmdArry[1] - if (cmd == 'state' and parame == 'start_chrome_driver_ok'): - chrome_start_ok = True - - strProcessIndex = str(self.processIndex) - strCode = "None" - strOp = "✅启动ChromeDriver程序✅" - strInfo = "OK"; - self.pyqtSignalToLogOpInfoTable.emit(strProcessIndex, strCode, strOp, strInfo) - - elif (cmd == 'state'): - errorMessage = cmdArry[2] - strProcessIndex = str(self.processIndex) - strCode = "None" - strOp = "❌启动ChromeDriver程序失败1❌" - strErroInfo = errorMessage + " " + parame; - self.pyqtSignalToLogErrorTable.emit(strProcessIndex, strCode, strOp, strErroInfo) - ############################################################# - - - - ############################################################# - ############################################################# - data = sock.recv(128) - if len(data) == 128: - cmdString = data.decode(); - cmdArry = cmdString.split('@') - cmd = cmdArry[0].strip('0') - parame = cmdArry[1] - if (cmd == 'state' and parame == 'shutdown_chrome_driver_ok'): - chrome_shutdown_ok = True - strProcessIndex = str(self.processIndex) - strCode = "None" - strOp = "✅关闭ChromeDriver程序✅" - strInfo = "OK"; - self.pyqtSignalToLogOpInfoTable.emit(strProcessIndex, strCode, strOp, strInfo) - - - else: - chrome_shutdown_ok = False - ############################################################# - - except Exception as ee: - print(ee) - errorMessage = ee.__str__() - - strProcessIndex = str(self.processIndex) - strCode = "None" - strOp = "❌线程错误❌" - strErroInfo = errorMessage; - self.pyqtSignalToLogErrorTable.emit(strProcessIndex, strCode, strOp, strErroInfo) - - finally: - sock.close() - - - - # 命令进程 开启 chromedriver - - ##connect to the process - sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - server_address = (self.connectAddress, self.connectPortInt) - sock.connect(server_address) - - ##send command - ############################################################# - strMsg0 = "start_chrome_driver@start_chrome_driver" - bytes_content = strMsg0.encode() - bytes_content = bytes_content.zfill(128) - assert (len(bytes_content) == 128) - # 🛠todo fix 128 个byte 很傻 - sock.sendall(bytes_content) - ############################################################# - - - - ##send command - ############################################################# - strMsg0 = "fetch_a_stock_data_to_mongodb@%s" % strCode - bytes_content = strMsg0.encode() - bytes_content = bytes_content.zfill(128) - assert (len(bytes_content) == 128) - # 🛠todo fix 128 个byte 很傻 - sock.sendall(bytes_content) - ############################################################# - - ##wait command execute result - ############################################################# - - while True: - - data = sock.recv(128) - if len(data) == 128: - cmdString = data.decode(); - cmdArry = cmdString.split('@') - cmd = cmdArry[0].strip('0') - parame = cmdArry[1] - if (cmd == 'state' and parame == 'fetch_a_stock_data_to_mongodb_open_web_page_ok'): - strProcessIndex = str(self.processIndex) - strOp = "✅成功打开网页✅" - strInfo = "OK"; - self.pyqtSignalToLogOpInfoTable.emit(strProcessIndex, strCode, strOp, strInfo) - - ##wait command execute result - ############################################################# - continue - - if (cmd == 'state' and parame == 'progress'): - prasePageProgress = cmdArry[2] - - strOp = "✅解析网页中🐞进度条报告" - strInfo = prasePageProgress; - self.pyqtSignalToLogOpInfoTable.emit(strProcessIndex, strCode, strOp, strInfo) - continue - elif (cmd == 'state' and parame == 'hearbeat'): - prasePageDateStr = cmdArry[2] - - strOp = "✅解析网页中🕷进度日期报告" - strInfo = prasePageDateStr; - - self.pyqtSignalToLogOpInfoTable.emit(strProcessIndex, strCode, strOp, strInfo) - continue - - elif (cmd == 'state' and parame == 'fetch_a_stock_data_to_mongodb_prase_web_page_ok'): - successPraseWebPageRecord = cmdArry[2] - iRecNewCount = int(successPraseWebPageRecord) - strOp = "✅写入🐜数据库OK" - strInfo = "📋新增%d条记录" % iRecNewCount; - self.pyqtSignalToLogOpInfoTable.emit(strProcessIndex, strCode, strOp, strInfo) - break - - elif (cmd == 'state' and parame == 'fetch_a_stock_data_to_mongodb_prase_web_page_failed'): - generalMessage = cmdArry[2] - strProcessIndex = str(self.processIndex) - strOp = "❌解析网页失败4❌" - strErroInfo = generalMessage; - self.pyqtSignalToLogErrorTable.emit(strProcessIndex, strCode, strOp,strErroInfo) - break - - elif (cmd == 'state' and parame == 'error_general_1'): - generalMessage = cmdArry[2] - strProcessIndex = str(self.processIndex) - strOp = "❌解析网页失败5❌" - strErroInfo = generalMessage; - self.pyqtSignalToLogErrorTable.emit(strProcessIndex, strCode, strOp,strErroInfo) - break - - - elif (cmd == 'state' and parame == 'fetch_a_stock_data_to_mongodb_open_web_page_failed'): - errorMessage = cmdArry[2] - - strProcessIndex = str(self.processIndex) - strOp = "❌打开网页失败7❌" - strErroInfo = errorMessage; - self.pyqtSignalToLogErrorTable.emit(strProcessIndex, strCode, strOp, strErroInfo) - break; - - elif (cmd == 'state' and parame == 'error_general_2'): - generalMessage = cmdArry[2] - strProcessIndex = str(self.processIndex) - strOp = "❌打开网页失败8❌" - strErroInfo = generalMessage; - self.pyqtSignalToLogErrorTable.emit(strProcessIndex, strCode, strOp, strErroInfo) - break - - elif (cmd == 'state' and parame == 'error_general_1'): - generalMessage = cmdArry[2] - strProcessIndex = str(self.processIndex) - strOp = "❌打开网页失败9❌" - strErroInfo = generalMessage; - self.pyqtSignalToLogErrorTable.emit(strProcessIndex, strCode, strOp, strErroInfo) - break - - elif (cmd == 'state'): - generalMessage = cmdArry[2] - if len(cmdArry) >= 3: - generalMessage = generalMessage + cmdArry[3] - - strProcessIndex = str(self.processIndex) - strOp = "❌解析网页失败10❌" - strErroInfo = generalMessage; - self.pyqtSignalToLogErrorTable.emit(strProcessIndex, strCode, strOp, strErroInfo) - break、、 -''' - -''' - def run00000(self): - ############################################################# - - #命令进程 开启 chromedriver - try: - - ##connect to the process - sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - server_address = (self.connectAddress, self.connectPortInt) - sock.connect(server_address) - - ##send command - ############################################################# - strMsg0 = "start_chrome_driver@start_chrome_driver" - bytes_content = strMsg0.encode() - bytes_content = bytes_content.zfill(128) - assert (len(bytes_content) == 128) - # 🛠todo fix 128 个byte 很傻 - sock.sendall(bytes_content) - ############################################################# - - - ##wait command execute result - ############################################################# - data = sock.recv(128) - if len(data) == 128: - - cmdString = data.decode(); - cmdArry = cmdString.split('@') - cmd = cmdArry[0].strip('0') - parame = cmdArry[1] - if (cmd == 'state' and parame == 'start_chrome_driver_ok'): - chrome_start_ok = True - - strProcessIndex = str(self.processIndex) - strCode = "None" - strOp = "✅启动ChromeDriver程序✅" - strInfo = "OK"; - self.pyqtSignalToLogOpInfoTable.emit(strProcessIndex, strCode, strOp, strInfo) - - - elif( cmd == 'state' and parame == 'start_chrome_driver_failed'): - errorMessage = cmdArry[2] - chrome_start_ok = False - - strProcessIndex = str(self.processIndex) - strCode = "None" - strOp = "❌启动ChromeDriver程序失败1❌" - strErroInfo = errorMessage; - self.pyqtSignalToLogErrorTable.emit(strProcessIndex, strCode, strOp, strErroInfo) - - elif( cmd == 'state' and parame == 'error_general'): - generalMessage = cmdArry[2] - strProcessIndex = str(self.processIndex) - strCode = "None" - strOp = "❌启动ChromeDriver程序失败2❌" - strErroInfo = generalMessage; - self.pyqtSignalToLogErrorTable.emit(strProcessIndex, strCode, strOp, strErroInfo) - - - ############################################################# - - else: - chrome_start_ok = False - except Exception as ee: - print(ee) - errorMessage = ee.__str__() - - strProcessIndex = str(self.processIndex) - strCode = "None" - strOp = "❌启动ChromeDriver程序3❌" - strErroInfo = errorMessage; - self.pyqtSignalToLogErrorTable.emit(strProcessIndex, strCode, strOp, strErroInfo) - - - finally: - sock.close() - ########################################### - ############################################ - ###############获取 记录 循环################ - ############################################ - - if chrome_start_ok: - - ############################################################# - # 循环获取股票列表,获取一个股,连接一次,然后 释放连接 - for iCodeIndex in range(self.lastTimeCheckPointStart, len(self.stockCodeList)): - - - strProcessIndex = str(self.processIndex) - strCode = self.stockCodeList[iCodeIndex] - - - try: - ##connect to the process - sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - server_address = (self.connectAddress, self.connectPortInt) - sock.connect(server_address) - - ##send command - ############################################################# - strMsg0 = "fetch_a_stock_data_to_mongodb@%s"%strCode - bytes_content = strMsg0.encode() - bytes_content = bytes_content.zfill(128) - assert (len(bytes_content) == 128) - # 🛠todo fix 128 个byte 很傻 - sock.sendall(bytes_content) - ############################################################# - - ##wait command execute result - ############################################################# - data = sock.recv(128) - if len(data) == 128: - - cmdString = data.decode(); - cmdArry = cmdString.split('@') - cmd = cmdArry[0].strip('0') - parame = cmdArry[1] - if (cmd == 'state' and parame == 'fetch_a_stock_data_to_mongodb_open_web_page_ok'): - - strProcessIndex = str(self.processIndex) - strOp = "✅成功打开网页✅" - strInfo = "OK"; - self.pyqtSignalToLogOpInfoTable.emit(strProcessIndex, strCode, strOp, strInfo) - - ##wait command execute result - ############################################################# - continue - - - if (cmd == 'state' and parame == 'progress'): - prasePageProgress = cmdArry[2] - - strOp = "✅解析网页中🐞进度条报告" - strInfo = prasePageProgress; - self.pyqtSignalToLogOpInfoTable.emit(strProcessIndex, strCode, strOp, strInfo) - continue - elif (cmd == 'state' and parame == 'hearbeat'): - prasePageDateStr = cmdArry[2] - - strOp = "✅解析网页中🕷进度日期报告" - strInfo = prasePageDateStr; - - self.pyqtSignalToLogOpInfoTable.emit(strProcessIndex, strCode, strOp, strInfo) - continue - - elif (cmd == 'state' and parame == 'fetch_a_stock_data_to_mongodb_prase_web_page_ok'): - successPraseWebPageRecord = cmdArry[2] - iRecNewCount = int(successPraseWebPageRecord) - strOp = "✅写入🐜数据库OK" - strInfo = "📋新增%d条记录" % iRecNewCount; - self.pyqtSignalToLogOpInfoTable.emit(strProcessIndex, strCode, strOp, strInfo) - break - - elif (cmd == 'state' and parame == 'fetch_a_stock_data_to_mongodb_prase_web_page_failed'): - generalMessage = cmdArry[2] - strProcessIndex = str(self.processIndex) - strOp = "❌解析网页失败4❌" - strErroInfo = generalMessage; - self.pyqtSignalToLogErrorTable.emit(strProcessIndex, strCode, strOp, - strErroInfo) - break - - elif (cmd == 'state' and parame == 'error_general_1'): - generalMessage = cmdArry[2] - strProcessIndex = str(self.processIndex) - strOp = "❌解析网页失败5❌" - strErroInfo = generalMessage; - self.pyqtSignalToLogErrorTable.emit(strProcessIndex, strCode, strOp, - strErroInfo) - break - - - elif (cmd == 'state'): - generalMessage= "_" - if len(cmdArry) >= 3: - generalMessage = cmdArry[2] - - strProcessIndex = str(self.processIndex) - strOp = "❌解析网页失败56❌" - strErroInfo = generalMessage; - self.pyqtSignalToLogErrorTable.emit(strProcessIndex, strCode, strOp,strErroInfo) - break; - - elif (cmd == 'state' and parame == 'fetch_a_stock_data_to_mongodb_open_web_page_failed'): - errorMessage = cmdArry[2] - - strProcessIndex = str(self.processIndex) - strOp = "❌打开网页失败7❌" - strErroInfo = errorMessage; - self.pyqtSignalToLogErrorTable.emit(strProcessIndex, strCode, strOp, strErroInfo) - break; - - elif (cmd == 'state' and parame == 'error_general_2'): - generalMessage = cmdArry[2] - strProcessIndex = str(self.processIndex) - strOp = "❌打开网页失败8❌" - strErroInfo = generalMessage; - self.pyqtSignalToLogErrorTable.emit(strProcessIndex, strCode, strOp, strErroInfo) - break - - elif (cmd == 'state' and parame == 'error_general_1'): - generalMessage = cmdArry[2] - strProcessIndex = str(self.processIndex) - strOp = "❌打开网页失败9❌" - strErroInfo = generalMessage; - self.pyqtSignalToLogErrorTable.emit(strProcessIndex, strCode, strOp, strErroInfo) - break - - elif (cmd == 'state'): - generalMessage = cmdArry[2] - if len(cmdArry) >= 3: - generalMessage = generalMessage + cmdArry[3] - - strProcessIndex = str(self.processIndex) - strOp = "❌解析网页失败10❌" - strErroInfo = generalMessage; - self.pyqtSignalToLogErrorTable.emit(strProcessIndex, strCode, strOp, strErroInfo) - break; - - ############################################################# - - - - except Exception as ee: - print(ee) - errorMessage = ee.__str__() - - strProcessIndex = str(self.processIndex) - strCode = strCode - strOp = "❌获取股票%s❌"%strCode - strErroInfo = errorMessage; - self.pyqtSignalToLogErrorTable.emit(strProcessIndex, strCode, strOp, strErroInfo) - - - finally: - sock.close() - - ############################################################# - #进程收到关闭请求 - if self.bThreadTobeOver == True: - - - strProcessIndex = str(self.processIndex) - strCode = "None" - strOp = "✅收到退出线程停止命令✅" - strInfo = "OK"; - self.pyqtSignalToLogOpInfoTable.emit(strProcessIndex, strCode, strOp, strInfo) - - break; - - pass - - ############################################################# - ###################### 所有记录 获取完毕 结束################################ - ############################################################# - # 命令进程 关闭 chromedriver - try: - ##connect to the process - sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - server_address = (self.connectAddress, self.connectPortInt) - sock.connect(server_address) - - data = sock.recv(128) - if len(data) == 128: - - cmdString = data.decode(); - cmdArry = cmdString.split('@') - cmd = cmdArry[0].strip('0') - parame = cmdArry[1] - if (cmd == 'state' and parame == 'shutdown_chrome_driver_ok'): - chrome_shutdown_ok = True - - strProcessIndex = str(self.processIndex) - strCode = "None" - strOp = "✅关闭ChromeDriver程序✅" - strInfo = "OK"; - self.pyqtSignalToLogOpInfoTable.emit(strProcessIndex, strCode, strOp, strInfo) - - - else: - chrome_shutdown_ok = False - else: - chrome_shutdown_ok = False - except Exception as ee: - print(ee) - finally: - sock.close() - ############################################################# - -''' diff --git a/QUANTAXIS_Monitor_GUI/TasksByThreading/QThread_GetStockList_Partition.py b/QUANTAXIS_Monitor_GUI/TasksByThreading/QThread_GetStockList_Partition.py deleted file mode 100644 index f8f2f13ec..000000000 --- a/QUANTAXIS_Monitor_GUI/TasksByThreading/QThread_GetStockList_Partition.py +++ /dev/null @@ -1,36 +0,0 @@ - -import time - -from PyQt5.QtCore import * -from PyQt5.QtGui import * -from PyQt5.QtWidgets import * -from PyQt5 import QtCore - -from QUANTAXIS.QAFetch.QAQuery import QA_fetch_stock_list - -from QUANTAXIS_Monitor_GUI.TasksByThreading.QThread_RootClass import * -''' - 获取股票列表 -''' -class QThread_GetStockList_Partition(QThread_RootClass): - - - - - def run(self): - #time.sleep(2) - print("QThread_GetStockList is running") - # 检查数据库是否已经开启 - - try: - self.stockListAll = QA_fetch_stock_list() - except Exception as ee: - # print(ee) - self.strTaskRunningResult = ee.__str__() - self.stockListAll = None - self.stockCountAll = 0 - return - - self.stockCountAll = len(self.stockListAll) - self.strTaskRunningResult= "成功获取 股票列表, 🔗 数据库成功 , 共 {} 个股票 😄".format(self.stockCountAll) - pass \ No newline at end of file diff --git a/QUANTAXIS_Monitor_GUI/TasksByThreading/QThread_RootClass.py b/QUANTAXIS_Monitor_GUI/TasksByThreading/QThread_RootClass.py deleted file mode 100644 index f67d15c8c..000000000 --- a/QUANTAXIS_Monitor_GUI/TasksByThreading/QThread_RootClass.py +++ /dev/null @@ -1,14 +0,0 @@ - -import time - -from PyQt5.QtCore import * -from PyQt5.QtGui import * -from PyQt5.QtWidgets import * -from PyQt5 import QtCore - -class QThread_RootClass(QThread): - ''' - ''' - strTaskRunningResult = "" - strTaskRunningLog = "" - diff --git a/QUANTAXIS_Monitor_GUI/TasksByThreading/__init__.py b/QUANTAXIS_Monitor_GUI/TasksByThreading/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/QUANTAXIS_Monitor_GUI/Utils/__init__.py b/QUANTAXIS_Monitor_GUI/Utils/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/QUANTAXIS_Monitor_GUI/Utils/mongodb_start_stop.sh b/QUANTAXIS_Monitor_GUI/Utils/mongodb_start_stop.sh deleted file mode 100644 index e353b1598..000000000 --- a/QUANTAXIS_Monitor_GUI/Utils/mongodb_start_stop.sh +++ /dev/null @@ -1,62 +0,0 @@ -#!/bin/sh -#MONGO_HOME=/root/usr/mongo -#MONGO_BIN=${MONGO_HOME}/bin -#MONGO_LOG=${MONGO_HOME}/log -#MONGO_DATA=${MONGO_HOME}/data -#MONGO_CONF=${MONGO_HOME}/conf - -MONGO_BIN_MONGOD=${MONGO_BIN}/mongod -#MONGO_CONF_MONGOD=${MONGO_CONF}/mongod.ini -MONGO_LOG_MONGOD=${MONGO_LOG}/mongodb.log -MONGO_BIN_MONGO=${MONGO_BIN}/mongo - -start() -{ - tmp=`ps -ef | grep ${MONGO_BIN_MONGOD} | wc -l`if [ $tmp -gt 1 ]; then - echo "The server arealdy started...abort!" - exit 1 - fi - deleteLock - cd ${MONGO_BIN} - ${MONGO_BIN_MONGOD} --dbpath ${MONGO_DATA} --port 27017 --fork --logpath ${MONGOD_LOG_MONGOD} --logappend - echo "Start MongoDB server in ${MONGO_BIN_MONGOD} OK!" -} - -stop() -{ - cd ${MONGO_BIN} - ${MONGO_BIN_MONGO} admin --eval "db.shutdownServer()" - echo "Stopped MongoDB server" -} - -usage() -{ - echo "Usage: $0 [start|stop|restart]" -} - -deleteLock() -{ - echo "Deleting mongod.lock" - cd ${MONGO_DATA} - /bin/rm -f mongod.lock - echo "Delete mongod.lock OK!" -} - -if [ $# -lt 1 ];then - usage - exit -fi - -if [ "$1" = "start" ];then - start - -elif [ "$1" = "stop" ];then - stop - -elif [ "$1" = "restart" ];then - stop - start - -else - usage -fi \ No newline at end of file diff --git a/QUANTAXIS_Monitor_GUI/__init__.py b/QUANTAXIS_Monitor_GUI/__init__.py deleted file mode 100644 index e69de29bb..000000000