def job_forget(self, persist=False): # 清除记忆 if persist is True: #save memory before forget them pass self.memory.clear() oplogs("memory erased")
def main(): itchat.auto_login(enableCmdQR=2, hotReload=True, loginCallback=init_robot) #itchat.start_receiving() oplogs("Harry bot is ready to run") itchat.run() oplogs("Harry Botter offline")
def group_reply(msg): # 处理support group中的命令 if gRobot.is_support_group(msg.User.NickName): oplogs("[%s:%s]%s" % (msg.User.NickName, msg.ActualNickName, msg['Text'])) #忽略at我的命令 if msg.isAt: return if USER_CMD in msg['Text'].lower( ): # contain 'harry' to trigger user command ret = gRobot.action_user(msg.Text, msg.User.NickName, msg.ActualNickName) # sleep 1 sec to avoid be ban time.sleep(1) if ret is not "": msg.user.send(ret) else: # 群消息监控 gRobot.listen( msg.User.NickName, # 群名 msg.ActualNickName, # 用户名 msg['Text'])
def __init__(self,debug=False): # 初始化tdx self.debug = debug oplogs("Loading stock mod...") self.api = TdxHq_API(heartbeat=(not debug),auto_retry=True) self.connect_to_tdx() self.load_stocklist() self.monitor_queue = dict()
def connect_to_tdx(self): random.shuffle(HZ_HOST_IPS) for ip in HZ_HOST_IPS: if self.api.connect(ip, 7709): oplogs("Connected to %s success" %ip) return else: oplogs("Connected to %s failed!!" %ip)
def __init__(self, debug=False, stopcb=None): oplogs("Harry Botter is rebooting") self.__init_robot(debug) self.stopcb = stopcb #self.__init_db() self.__init_jobs() oplogs("Harry Botter is online")
def init_robot(): global gRobot # 默认在windows下开启调试模式 loadcfg() gRobot = HarryBotter(debug=(os.name is 'nt'), stopcb=quitwx) gRobot.install_mods(StockMod()) gRobot.add_groups(supportgroup) gRobot.subscribe(sendto) oplogs("Harry bot init accomplished")
def sendto(subscriber, msg): # callback function for robot send message to subscribers if subscriber is 'filehelper': itchat.send(msg, 'filehelper') else: itchat.get_chatrooms(update=True, contactOnly=True) chatrooms = itchat.search_chatrooms(name=subscriber) if len(chatrooms) > 0: oplogs('sending message to %s' % (chatrooms[0]['UserName'])) chatrooms[0].send(msg)
def loadcfg(): global supportgroup cur_path = os.path.dirname(os.path.realpath(__file__)) #获取config.ini的路径 config_path = os.path.join(cur_path, 'config.ini') conf = configparser.ConfigParser() conf.read(config_path, encoding='utf-8') supportgroup = conf.get('default', 'supportgroups').split(',') oplogs("supportgroups loaded")
def add_to_monitor_group(self,group,stock): if stock.isdigit(): code = stock else: code = self.stockrdict[stock] if group in self.monitor_queue.keys(): if code not in self.monitor_queue[group]: self.monitor_queue[group].append(code) else: self.monitor_queue[group] = [code] oplogs("add_to_monitor_group called:%s %s" %(group, stock))
def __init_db(self): # 创建数据库数据库用于永久记忆 self.conn = sqlite3.connect('messages.db') self.cursor = self.conn.cursor() self.cursor.execute( 'create table if not exists msgqueue (id integer primary key autoincrement, date TEXT, groupname TEXT, user TEXT, msg TEXT)' ) self.cursor.execute( 'create table if not exists monitorstocks (id integer primary key autoincrement, groupname TEXT, code TEXT)' ) self.cursor.commit() oplogs("[%s]messages.db connected")
def del_from_list(self, group, stock): # group, group name # stock, stock name # remove stock from group if stock.isdigit(): code = stock else: code = self.stockrdict[stock] if group in self.monitor_queue.keys(): if code in self.monitor_queue[group]: self.monitor_queue[group].remove(code) oplogs("del_from_list called:%s %s" %(group, stock))
def __init_jobs(self): self.sched = BackgroundScheduler() # 添加任务作业 # 每天清理一次缓存 #self.sched.add_job(self.job_clean_cache, trigger='cron', day_of_week='*',hour=1, minute=0, second=0) # 提供给group的5分钟检测 self.sched.add_job(self.job_stock_monitor, trigger='cron', id='job_stock_monitor', minute="*/5") #, next_run_time=None) # 交易日9:30:15生成开盘报告 self.sched.add_job(self.job_open_scan, trigger='cron', day_of_week='0-4', hour=9, minute=30, second=15) # 交易日11:30--13:00之间关闭扫描 self.sched.add_job(self.job_close_scan, trigger='cron', day_of_week='0-4', hour=11, minute=30, second=15) self.sched.add_job(self.job_open_scan, trigger='cron', day_of_week='0-4', hour=13, minute=0, second=0) # 交易日15:05:00生成收盘报告 self.sched.add_job(self.job_close_scan, trigger='cron', day_of_week='0-4', hour=15, minute=5, second=0) # 启动调度器 self.sched.start() oplogs("schedulers started")
def job_stock_monitor(self, valve=3.0): if self.enable is False: return oplogs("job_stock_monitor triggerred") group_alarms = self.stockmod.get_alarms(valve) for (group, alarms) in group_alarms.items(): notice = "" for alarm in alarms: # alarm = [stockname,price,change,highlow,closeopen] alarm_content = "5分钟涨跌\n[%s %.2f%%]幅度:%.2f%%, 波动:%.2f%%\n" % ( alarm[0], alarm[2], alarm[4], alarm[3]) notice += alarm_content if len(notice) > 0: print(notice) self.mouth(group, notice) time.sleep(1)
def save_to_db(self): oplogs("save_to_db called") # 保存消息 for msg in self.memory: sql = "INSERT INTO msgqueue VALUES (%s,%s,%s,%s)" % ( msg[0], msg[1], msg[2], msg[3]) self.cursor.execute(sql) # 保存监控列表 for (key, value) in self.stockmod.monitor_queue.items(): for code in value: # date TEXT, group TEXT, code TEXT # date = time.strftime("%Y-%m-%d %H:%M:%S") sql = "INSERT INTO monitorstocks VALUES (%s,%s)" % (key, code) self.cursor.execute(sql) self.conn.commit()
def get_stock_daily(self, code): # 计算当日涨跌 market = self.get_market(code) data_day = self.api.get_security_quotes([(market,code)]) # get daily changes if self.debug: oplogs("get_stock_daily called") #print(self.api.to_df(data_day).ix[:,0:8]) last_close = data_day[0]['last_close'] current_price = data_day[0]['price'] if last_close >0: #正常情况 change = (current_price/last_close - 1)*100 else: change = 0 return current_price, change
def get_stock_price(self, code): if code not in self.stockcode: return "" market = self.get_market(code) oplogs("get_stock_price called,code=%s,market=%s" %(code,market)) price = self.api.get_security_quotes([(market,code)]) last_close = price[0]['last_close'] current_price = price[0]['price'] if last_close >0: change = (current_price/last_close - 1)*100 else: change = 0 result = "[%s]%.2f 涨幅:%.2f%%" %(self.stockdict[code],current_price,change ) return result
def text_reply(msg): # use filehelper as control console if msg.user['UserName'] == "filehelper": oplogs("['filehelper']%s" % (msg['Text'])) usercmd = msg.Text.split() if usercmd[0] == 'harry': ret = gRobot.action_user(msg.Text, msg.User.UserName, msg.User.UserName) time.sleep(1) if ret is not "": msg.user.send(ret) else: ret = gRobot.action(msg.Text) time.sleep(1) if ret is not "": msg.user.send(ret)
def load_stocklist(self): try: oplogs("get_stock_basics() ...") self.stocklist = ts.get_stock_basics() oplogs("get_stock_basics() load from remote success") except: # 如果加载远程股票列表失败, 从本地列表读取 oplogs("get_stock_basics() timeout, use local cached file instead") cur_path=os.path.dirname(os.path.realpath(__file__)) stocklist_path=os.path.join(cur_path,'all.csv') df = pd.read_csv(stocklist_path, dtype={'code':'object'},encoding='GBK') df = df.set_index('code') self.stocklist = df # remove space in stock name self.stocklist['name'] = self.stocklist['name'].str.replace(' ','') self.stocklist.drop(self.stocklist[self.stocklist.name == '机器人'].index, inplace=True) df_index = pd.DataFrame([['999999','上证指数'], ['399001','深证成指'], ['399006','创业板指']], index=['999999','399001','399006'], columns=['code', 'name']) self.stocklist = self.stocklist.append(df_index) # create dict and list to shorten search time self.stockdict = self.stocklist.to_dict()["name"] self.stockrdict = {value:key for key,value in self.stockdict.items()} self.stockcode = self.stocklist.index.to_list() self.stockname = self.stocklist.name.to_list()
def get_stock_min(self, code, min=5): market = self.get_market(code) data_min = self.api.get_security_bars(0,market, code, 0, 1) # 5 min K bar if self.debug: oplogs("get_stock_min called") #print(self.api.to_df(data_min).ix[:,0:8]) open = data_min[0]['open'] close = data_min[0]['close'] high = data_min[0]['high'] low = data_min[0]['low'] if low >0 and open>0: # 波动范围 change_high_low = (high-low)/low*100 # 涨跌幅 change_close_open = (close-open)/open*100 else: change_high_low = 0 change_close_open = 0 return change_high_low, change_close_open
def action_user(self, cmd, group, user): cmds = cmd.lower().split() #"命令格式: # [添加监控]harry 股票名 # [删除监控]harry del 股票名 # [显示群推荐]harry 本群推荐 # [显示群数据统计]harry stat # [显示报告]harry report"] # user 用户命令 if len(cmds) == 1: return random.choice(auto_replys) if ('list' in cmds[1]) or ('本群推荐' in cmds[1]): oplogs("action_user:本群推荐 [%s]" % cmd) return self.stockmod.get_group_stock_price(group) elif 'del' == cmds[1]: return self.stockmod.del_from_list(group, cmds[2]) elif 'stat' in cmds[1]: boottime = datetime.now() - self.starttime boothour = int(boottime.seconds / 3600) bootmin = int(boottime.seconds % 3600 / 60) stat = "机器人已运行:{}天{}小时{}分钟\n股价扫描任务:{}".format( boottime.days, boothour, bootmin, self.sched.state) return stat elif 'report' in cmds[1]: return "建设中" elif 'help' in cmds[1]: oplogs("action_user:help called") return auto_replys[0] elif 'ver' in cmds[1]: return HR__VERSION elif '启动' in cmds[1]: return "臣在" elif '关闭' in cmds[1]: return "跪安" else: oplogs("action_user:harry [stock] called %s" % cmd) if self.stockmod.isvalid_stock(cmds[1]): self.add_stock(group, cmds[1]) return self.show_stock(cmds[1]) return ""
def stop_jobs(self): if self.sched == None: self.sched.shutdown() oplogs("schedulers stopped")
def job_open_scan(self): oplogs("job_open_scan triggerred") self.job_stock_monitor() self.sched.resume_job(job_id="job_stock_monitor")
def quitwx(): oplogs("About to shutdown Harry Botter") itchat.send("harry botter stopped", 'filehelper') itchat.logout()
def job_close_scan(self): oplogs("job_close_scan triggerred") self.sched.pause_job(job_id="job_stock_monitor") oplogs("job_stock_monitor paused")
def __del__(self): oplogs("Harry Botter is shutting down~~~") self.stop_jobs()
def subscribe(self, msgSend): self.mouth = msgSend oplogs('Robot unmuted.')
def __del__(self): oplogs("Unloading stock mod...") self.api.disconnect()
def unsubscribe(self): self.mouth = None oplogs('Robot muted.')