python_PyQt5开发股票指定区间K线操作工具_裸K

news2024/12/23 14:28:20

目录

写在前面:

工具使用演示:

代码: 

导入包

横坐标控件、K线控件、带查询下拉列表控件

K线图控件

主界面代码

执行代码


写在前面:

继前面文章提到筛出低位股票后,想逐一查看这些股票今年的K线走势,发现股票软件要查看指定时间范围的K线不是很方便,所以萌生了开发这个工具的想法。另外,考虑到后续可能还会有很多数据在股票软件上不方便查看,就觉得开发个可用的工具十分必要。

工具使用演示:

1 按钮“选择股票日数据所在目录”:股票日数据目录。

注:这里的股票日数据来自优矿,所以涉及到日数据字段的操作,参看优矿官网上的数据说明。

2 按钮“选择股票代码和股票名键值对json文件”:这里选择放置要查看的股票列表{股票代码:股票名}的json文件

3 第2步选择json文件后,程序会读取股票名信息放入下拉列表中

4 全局区间控制区域:这里设置了时间区间,那么下面K线图就都会显示这个区间,不需要一个个股票设置

5 K线图展示区域

代码: 

导入包

import os,sys,json
import pandas as pd
from threading import Thread
from typing import Dict,List,Any
from PyQt5 import QtCore,QtWidgets,QtGui
from PyQt5.QtCore import Qt
import pyqtgraph as pg
pg.setConfigOption('background','w')
pg.setConfigOption('foreground','k')

横坐标控件、K线控件、带查询下拉列表控件

class RotateAxisItem(pg.AxisItem):
    def drawPicture(self, p, axisSpec, tickSpecs, textSpecs):
        p.setRenderHint(p.Antialiasing,False)
        p.setRenderHint(p.TextAntialiasing,True)

        ## draw long line along axis
        pen,p1,p2 = axisSpec
        p.setPen(pen)
        p.drawLine(p1,p2)
        p.translate(0.5,0)  ## resolves some damn pixel ambiguity

        ## draw ticks
        for pen,p1,p2 in tickSpecs:
            p.setPen(pen)
            p.drawLine(p1,p2)

        ## draw all text
        # if self.tickFont is not None:
        #     p.setFont(self.tickFont)
        p.setPen(self.pen())
        for rect,flags,text in textSpecs:
            # this is the important part
            p.save()
            p.translate(rect.x(),rect.y())
            p.rotate(-30)
            p.drawText(int(-rect.width()),int(rect.height()),int(rect.width()),int(rect.height()),flags,text)
            # restoring the painter is *required*!!!
            p.restore()

class CandlestickItem(pg.GraphicsObject):
    def __init__(self, data):
        pg.GraphicsObject.__init__(self)
        self.data = data  ## data must have fields: time, open, close, min, max
        self.generatePicture()

    def generatePicture(self):
        ## pre-computing a QPicture object allows paint() to run much more quickly,
        ## rather than re-drawing the shapes every time.
        self.picture = QtGui.QPicture()
        p = QtGui.QPainter(self.picture)
        p.setPen(pg.mkPen('d'))
        w = (self.data[1][0] - self.data[0][0]) / 3.
        for (t, open, close, min, max) in self.data:
            p.drawLine(QtCore.QPointF(t, min), QtCore.QPointF(t, max))
            if open < close:
                p.setBrush(pg.mkBrush('r'))
            else:
                p.setBrush(pg.mkBrush('g'))
            p.drawRect(QtCore.QRectF(t-w, open, w * 2, close - open))
        p.end()

    def paint(self, p, *args):
        p.drawPicture(0, 0, self.picture)

    def boundingRect(self):
        ## boundingRect _must_ indicate the entire area that will be drawn on
        ## or else we will get artifacts and possibly crashing.
        ## (in this case, QPicture does all the work of computing the bouning rect for us)
        return QtCore.QRectF(self.picture.boundingRect())

class ExtendedComboBox(QtWidgets.QComboBox):
    def __init__(self, parent=None):
        super(ExtendedComboBox, self).__init__(parent)

        self.setFocusPolicy(Qt.StrongFocus)
        self.setEditable(True)

        # add a filter model to filter matching items
        self.pFilterModel = QtCore.QSortFilterProxyModel(self)
        self.pFilterModel.setFilterCaseSensitivity(Qt.CaseInsensitive)
        self.pFilterModel.setSourceModel(self.model())

        # add a completer, which uses the filter model
        self.completer = QtWidgets.QCompleter(self.pFilterModel, self)
        # always show all (filtered) completions
        self.completer.setCompletionMode(QtWidgets.QCompleter.UnfilteredPopupCompletion)
        self.setCompleter(self.completer)

        # connect signals
        self.lineEdit().textEdited.connect(self.pFilterModel.setFilterFixedString)
        self.completer.activated.connect(self.on_completer_activated)

    # on selection of an item from the completer, select the corresponding item from combobox
    def on_completer_activated(self, text):
        if text:
            index = self.findText(text)
            self.setCurrentIndex(index)
            self.activated[str].emit(self.itemText(index))

    # on model change, update the models of the filter and completer as well
    def setModel(self, model):
        super(ExtendedComboBox, self).setModel(model)
        self.pFilterModel.setSourceModel(model)
        self.completer.setModel(self.pFilterModel)

    # on model column change, update the model column of the filter and completer as well
    def setModelColumn(self, column):
        self.completer.setCompletionColumn(column)
        self.pFilterModel.setFilterKeyColumn(column)
        super(ExtendedComboBox, self).setModelColumn(column)

K线图控件

class K_Widget(QtWidgets.QWidget):
    def __init__(self):
        super().__init__()
        self.init_data()
        self.init_ui()
        pass
    def init_data(self):
        self.whole_header = None
        self.whole_df = None
        self.whole_pd_header = None
        self.whole_xTick = None

        self.current_df = None
        self.current_data = None
        self.dur_len = 20
        pass
    def init_ui(self):
        self.duration_label = QtWidgets.QLabel('左边界~右边界')

        self.left_label = QtWidgets.QLabel('左边:')
        self.left_slider = QtWidgets.QSlider(Qt.Horizontal)
        self.left_slider.valueChanged.connect(self.left_slider_valueChanged)
        self.right_slider = QtWidgets.QSlider(Qt.Horizontal)
        self.right_slider.valueChanged.connect(self.right_slider_valueChanged)
        self.right_label = QtWidgets.QLabel(':右边')

        check_btn = QtWidgets.QPushButton('确定')
        check_btn.clicked.connect(self.check_btn_clicked)

        layout_top = QtWidgets.QHBoxLayout()
        layout_top.addWidget(self.duration_label)
        layout_top.addWidget(self.left_label)
        layout_top.addWidget(self.left_slider)
        layout_top.addWidget(self.right_slider)
        layout_top.addWidget(self.right_label)
        layout_top.addWidget(check_btn)

        xax = RotateAxisItem(orientation='bottom')
        xax.setHeight(h=50)
        self.pw = pg.PlotWidget(axisItems={'bottom': xax})
        self.pw.setMouseEnabled(x=True, y=False)
        # self.pw.enableAutoRange(x=False,y=True)
        self.pw.setAutoVisible(x=False, y=True)

        layout = QtWidgets.QVBoxLayout()
        layout.addLayout(layout_top)
        layout.addWidget(self.pw)
        self.setLayout(layout)
        pass

    def first_setData(self,data:Dict):
        whole_header = data['whole_header']
        whole_df = data['whole_df']
        whole_pd_header = data['whole_pd_header']

        whole_xTick = whole_df['xTick'].values.tolist()

        self.whole_header = whole_header
        self.whole_df = whole_df
        self.whole_pd_header = whole_pd_header
        self.whole_xTick = whole_xTick

        self.left_slider.setMinimum(0)
        self.left_slider.setMaximum(len(whole_xTick)-1)
        self.right_slider.setMinimum(0)
        self.right_slider.setMaximum(len(whole_xTick)-1)

        self.left_slider.setValue(0)
        self.right_slider.setValue(len(whole_xTick)-1)
        self.left_label.setText(f"左边:{whole_xTick[0]}")
        self.right_label.setText(f"{whole_xTick[-1]}:右边")

        self.current_df = self.whole_df.copy()
        self.caculate_and_show_data()
        pass

    def caculate_and_show_data(self):
        df = self.current_df.copy()
        df.reset_index(inplace=True)
        df['x'] = [i for i in range(len(df))]
        xTick = df['xTick'].values.tolist()
        xTick00 = []
        dur_num = int(len(xTick)/self.dur_len)
        if dur_num > 2:
            for i in range(0,len(xTick),dur_num):
                xTick00.append((i,xTick[i]))
            pass
        else:
            for i,item in enumerate(xTick):
                xTick00.append((i,item))
            pass
        candle_data = []
        for i,row in df.iterrows():
            candle_data.append((row['x'],row['open'],row['close'],row['lowest'],row['highest']))
        self.current_data = df.loc[:,self.whole_pd_header].values.tolist()
        y_min = df['lowest'].min()
        y_max = df['highest'].max()

        # 开始配置显示内容
        self.pw.clear()

        self.duration_label.setText(f"{xTick[0]}~{xTick[-1]}")

        xax = self.pw.getAxis('bottom')
        xax.setTicks([xTick00])

        self.vb = self.pw.getViewBox()
        self.vb.setLimits(yMin=y_min,yMax=y_max)

        candle_fixed_target = CandlestickItem(candle_data)
        self.pw.addItem(candle_fixed_target)

        self.vLine = pg.InfiniteLine(angle=90,movable=False)
        self.hLine = pg.InfiniteLine(angle=0,movable=False)
        self.label = pg.TextItem()

        self.pw.addItem(self.vLine,ignoreBounds=True)
        self.pw.addItem(self.hLine,ignoreBounds=True)
        self.pw.addItem(self.label,ignoreBounds=True)

        self.proxy = pg.SignalProxy(self.pw.scene().sigMouseMoved,rateLimit=60,slot=self.mouseMoved)
        self.pw.enableAutoRange()
        self.pw.setAutoVisible()
        pass

    def mouseMoved(self,evt):
        pos = evt[0]
        if self.pw.sceneBoundingRect().contains(pos):
            mousePoint = self.vb.mapSceneToView(pos)
            index = int(mousePoint.x())
            if index>=0 and index<len(self.current_data):
                target_data = self.current_data[index]
                html_str = ''
                for i,item in enumerate(self.whole_header):
                    html_str += f"<br/>{item}:{target_data[i]}"
                self.label.setHtml(html_str)
                self.label.setPos(mousePoint.x(),mousePoint.y())
                pass
            self.vLine.setPos(mousePoint.x())
            self.hLine.setPos(mousePoint.y())
            pass
        pass

    def left_slider_valueChanged(self):
        left_value = self.left_slider.value()
        self.left_label.setText(f"左边:{self.whole_xTick[left_value]}")
        pass
    def right_slider_valueChanged(self):
        right_value = self.right_slider.value()
        self.right_label.setText(f"{self.whole_xTick[right_value]}:右边")
        pass
    def check_btn_clicked(self):
        left_value = self.left_slider.value()
        right_value = self.right_slider.value()

        if right_value <= left_value:
            QtWidgets.QMessageBox.information(
                self,
                '提示',
                '左边界不能大于右边界',
                QtWidgets.QMessageBox.Yes
            )
            return
        self.current_df = self.whole_df.iloc[left_value:right_value].copy()
        self.caculate_and_show_data()
        pass
    pass

主界面代码

class KMainWidget(QtWidgets.QWidget):
    signal_excute = QtCore.pyqtSignal(object)
    def __init__(self):
        super().__init__()

        self.thread_caculate: Thread = None

        self.init_data()
        self.init_ui()
        self.register_event()
        self.progress_init()
        self.global_duration_checkbox_clicked()
        pass
    def init_data(self):
        self.please_select_str: str = '-- 请选择 --'
        self.current_stock_name: str = None
        self.ticker_name_map: Dict[str,str] = {}
        self.name_ticker_map: Dict[str,str] = {}
        self.stockname_list: List[str] = []
        self.target_column_list: List[str] = ['xTick','open','close','highest','lowest']
        pass
    def init_ui(self):
        self.setWindowTitle('股票指定区间K线工具')

        self.caculate_progress = QtWidgets.QProgressBar()
        self.caculate_status_label = QtWidgets.QLabel()

        layout_progress = QtWidgets.QHBoxLayout()
        layout_progress.addWidget(self.caculate_progress)
        layout_progress.addWidget(self.caculate_status_label)

        choice_stock_dir_btn = QtWidgets.QPushButton('选择股票日数据所在目录')
        choice_stock_dir_btn.clicked.connect(self.choice_stock_dir_btn_clicked)
        self.stock_dir_lineedit = QtWidgets.QLineEdit()
        choice_stockname_map_file_btn = QtWidgets.QPushButton('选择股票代码和股票名键值对json文件')
        choice_stockname_map_file_btn.clicked.connect(self.choice_stockname_map_file_btn_clicked)
        self.stockname_json_lineedit = QtWidgets.QLineEdit()

        layout_one = QtWidgets.QFormLayout()
        layout_one.addRow(choice_stock_dir_btn,self.stock_dir_lineedit)
        layout_one.addRow(choice_stockname_map_file_btn,self.stockname_json_lineedit)

        tip_label = QtWidgets.QLabel('股票列表')
        self.stock_combox = ExtendedComboBox()
        self.stock_combox.addItem(self.please_select_str)
        self.stock_combox.currentTextChanged.connect(self.stock_combox_currentTextChanged)

        self.global_duration_checkbox = QtWidgets.QCheckBox('全局区间')
        self.global_duration_checkbox.clicked.connect(self.global_duration_checkbox_clicked)
        self.left_point = QtWidgets.QDateEdit()
        self.left_point.setDisplayFormat('yyyy-MM-dd')
        self.left_point.setCalendarPopup(True)
        self.right_point = QtWidgets.QDateEdit()
        self.right_point.setDisplayFormat('yyyy-MM-dd')
        self.right_point.setCalendarPopup(True)
        self.global_duration_btn = QtWidgets.QPushButton('确定')
        self.global_duration_btn.clicked.connect(self.global_duration_btn_clicked)

        layout_two = QtWidgets.QHBoxLayout()
        layout_two.addWidget(tip_label)
        layout_two.addWidget(self.stock_combox)
        layout_two.addStretch(1)
        layout_two.addWidget(self.global_duration_checkbox)
        layout_two.addWidget(self.left_point)
        layout_two.addWidget(self.right_point)
        layout_two.addWidget(self.global_duration_btn)

        layout_up = QtWidgets.QVBoxLayout()
        layout_up.addLayout(layout_one)
        layout_up.addLayout(layout_two)

        groupbox = QtWidgets.QGroupBox('全局设置',self)
        groupbox.setLayout(layout_up)

        self.title_label = QtWidgets.QLabel('股票简称')
        self.title_label.setAlignment(QtCore.Qt.AlignCenter)
        self.title_label.setStyleSheet('QLabel{font-size:16px;font-weight:bold}')

        self.k_widget = K_Widget()

        layout_three = QtWidgets.QVBoxLayout()
        layout_three.addWidget(self.title_label)
        layout_three.addWidget(self.k_widget)

        up_btn = QtWidgets.QPushButton('上一个')
        up_btn.clicked.connect(self.up_btn_clicked)
        down_btn = QtWidgets.QPushButton('下一个')
        down_btn.clicked.connect(self.down_btn_clicked)

        layout_four = QtWidgets.QVBoxLayout()
        layout_four.addWidget(up_btn)
        layout_four.addWidget(down_btn)

        layout_five = QtWidgets.QHBoxLayout()
        layout_five.addLayout(layout_three,11)
        layout_five.addLayout(layout_four,1)

        layout = QtWidgets.QVBoxLayout()
        layout.addLayout(layout_progress)
        layout.addWidget(groupbox)
        layout.addLayout(layout_five)
        self.setLayout(layout)
        pass
    def register_event(self):
        self.signal_excute.connect(self.process_excute_event)
        pass
    def process_excute_event(self,data:Dict):
        mark_str = data['mark_str']
        status = data['status']
        if mark_str == 'show_stock_candle':
            if status == 'error':
                self.thread_caculate = None
                self.progress_finished()
                QtWidgets.QMessageBox.information(
                    self,
                    '提示',
                    data['data'],
                    QtWidgets.QMessageBox.Yes
                )
                return
            else:
                self.title_label.setText(self.current_stock_name)
                self.k_widget.first_setData(data['data'])

                self.thread_caculate = None
                self.progress_finished()
                pass
        pass
    def choice_stock_dir_btn_clicked(self):
        path = QtWidgets.QFileDialog.getExistingDirectory(
            self,
            '打开股票日数据所在目录',
            '.'
        )
        if not path:
            return
        self.stock_dir_lineedit.setText(path)
        pass
    def choice_stockname_map_file_btn_clicked(self):
        path,_ = QtWidgets.QFileDialog.getOpenFileName(
            self,
            '选择股票代码与名称键值对json文件',
            '.',
            'JOSN(*.json)'
        )
        if not path:
            return
        self.stockname_json_lineedit.setText(path)
        with open(path,'r',encoding='utf-8') as fr:
            self.ticker_name_map = json.load(fr)
        self.name_ticker_map = {}
        for key,val in self.ticker_name_map.items():
            self.name_ticker_map[val] = key
        self.stockname_list = list(self.name_ticker_map.keys())
        self.stock_combox.clear()
        self.stock_combox.addItem(self.please_select_str)
        self.stock_combox.addItems(self.stockname_list)
        pass
    def stock_combox_currentTextChanged(self,txt:str):
        cur_txt = self.stock_combox.currentText()
        if not cur_txt \
                or cur_txt==self.current_stock_name \
                or cur_txt==self.please_select_str:
            return
        self.current_stock_name = cur_txt
        self.pre_caculate_data()
        pass
    def global_duration_checkbox_clicked(self):
        if self.global_duration_checkbox.isChecked():
            # 勾选,则表示要遵从全局区间
            self.left_point.setDisabled(False)
            self.right_point.setDisabled(False)
            self.global_duration_btn.setDisabled(False)
            pass
        else:
            # 没有勾选,表示不设全局区间
            self.left_point.setDisabled(True)
            self.right_point.setDisabled(True)
            self.global_duration_btn.setDisabled(True)
            pass
        pass
    def global_duration_btn_clicked(self):
        if self.current_stock_name:
            self.pre_caculate_data()
        pass
    def up_btn_clicked(self):
        if not self.current_stock_name:
            self.current_stock_name = self.stockname_list[-1]
        else:
            try:
                cur_index = self.stockname_list.index(self.current_stock_name)
                if cur_index == 0:
                    cur_index = len(self.stockname_list)-1
                else:
                    cur_index = cur_index -1
                self.current_stock_name = self.stockname_list[cur_index]
            except:
                QtWidgets.QMessageBox.information(
                    self,
                    '提示',
                    f'{self.current_stock_name}在股票列表中不存在',
                    QtWidgets.QMessageBox.Yes
                )
                return
        self.pre_caculate_data()
        pass
    def down_btn_clicked(self):
        if not self.current_stock_name:
            self.current_stock_name = self.stockname_list[0]
        else:
            try:
                cur_index = self.stockname_list.index(self.current_stock_name)
                if cur_index >= len(self.stockname_list) - 1:
                    cur_index = 0
                else:
                    cur_index = cur_index + 1
                self.current_stock_name = self.stockname_list[cur_index]
            except:
                QtWidgets.QMessageBox.information(
                    self,
                    '提示',
                    f'{self.current_stock_name}在股票列表中不存在',
                    QtWidgets.QMessageBox.Yes
                )
                return
        self.pre_caculate_data()
        pass
    def pre_caculate_data(self):
        # 股票日数据目录是否已经指定
        daily_dir = self.stock_dir_lineedit.text()
        daily_dir = daily_dir.strip()
        if not daily_dir:
            QtWidgets.QMessageBox.information(
                self,
                '提示',
                '请选择股票日数据目录',
                QtWidgets.QMessageBox.Yes
            )
            return
        if not self.ticker_name_map:
            QtWidgets.QMessageBox.information(
                self,
                '提示',
                '请选择股票代码股票名键值对json文件',
                QtWidgets.QMessageBox.Yes
            )
            return
        daily_file_path = daily_dir + os.path.sep + self.name_ticker_map[self.current_stock_name] + '.csv'
        if not os.path.exists(daily_file_path):
            QtWidgets.QMessageBox.information(
                self,
                '提示',
                f'不存在{self.current_stock_name}的日数据文件',
                QtWidgets.QMessageBox.Yes
            )
            return

        # 判断是否有全局设置
        if self.global_duration_checkbox.isChecked():
            global_dur_yeah = True
            left_point = self.left_point.date().toString('yyyy-MM-dd')
            right_point = self.right_point.date().toString('yyyy-MM-dd')
            global_dur_list = [left_point,right_point]
            pass
        else:
            global_dur_yeah = False
            global_dur_list = []
            pass
        mark_str = 'show_stock_candle'
        pre_map = {
            'global_dur_yeah':global_dur_yeah,
            'global_dur_list':global_dur_list,
            'daily_file_path':daily_file_path
        }
        self.start_caculate_thread(mark_str,pre_map)
        self.progress_busy()
        pass

    def start_caculate_thread(self,mark_str:str,data:Dict[str,Any]):
        if self.thread_caculate:
            QtWidgets.QMessageBox.information(
                self,
                '提示',
                '线程正在执行任务,请稍后。。。',
                QtWidgets.QMessageBox.Yes
            )
            return
        self.thread_caculate = Thread(
            target=self.running_caculate_thread,
            args=(
                mark_str, data,
            )
        )
        self.thread_caculate.start()
        self.progress_busy()
        pass
    def running_caculate_thread(self,mark_str:str,data:Dict[str,Any]):
        if mark_str == 'show_stock_candle':
            global_dur_yeah = data['global_dur_yeah']
            global_dur_list = data['global_dur_list']
            daily_file_path = data['daily_file_path']

            df = pd.read_csv(daily_file_path,encoding='utf-8')
            # 去除停牌的数据
            df = df.loc[df['openPrice']>0].copy()
            # 计算前复权数据
            df['open'] = df['openPrice']*df['accumAdjFactor']
            df['close'] = df['closePrice']*df['accumAdjFactor']
            df['highest'] = df['highestPrice']*df['accumAdjFactor']
            df['lowest'] = df['lowestPrice']*df['accumAdjFactor']
            df['xTick'] = df['tradeDate']

            if global_dur_yeah:
                df['o_date'] = pd.to_datetime(df['tradeDate'])
                df = df.loc[(df['o_date']>=global_dur_list[0]) & (df['o_date']<=global_dur_list[1])].copy()
                if len(df)<2:
                    res_map = {
                        'mark_str': mark_str,
                        'status': 'error',
                        'data': '全局区间对应的时间段没有数据'
                    }
                    self.signal_excute.emit(res_map)
                    return
            res_data = {
                'whole_df':df,
                'whole_header':['日期','开盘','收盘','最高','最低'],
                'whole_pd_header':self.target_column_list
            }
            res_map = {
                'mark_str': mark_str,
                'status': 'success',
                'data': res_data
            }
            self.signal_excute.emit(res_map)
            pass
        pass
    def progress_init(self) -> None:
        self.caculate_progress.setValue(0)
        self.caculate_status_label.setText('无任务')
    def progress_busy(self) -> None:
        self.caculate_progress.setRange(0, 0)
        self.caculate_status_label.setText('正在执行')
    def progress_finished(self) -> None:
        self.caculate_progress.setRange(0, 100)
        self.caculate_progress.setValue(100)
        self.caculate_status_label.setText('执行完毕')
        pass
    pass

执行代码

if __name__ == '__main__':
    QtCore.QCoreApplication.setAttribute(QtCore.Qt.HighDpiScaleFactorRoundingPolicy.PassThrough)
    app = QtWidgets.QApplication(sys.argv)
    main_window = KMainWidget()
    main_window.showMaximized()
    app.exec()
    pass

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/772598.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

香港视频直播服务器需要多大的带宽(带宽计算方式)

​  香港视频直播服务器需要多大的带宽(怎么计算带宽大小)。目前短视频行业兴起&#xff0c;有许多人也想利用香港服务器搭建一个直播平台&#xff0c;但无奈不知道怎么选择资源大小&#xff0c;或者说什么样的配置能够满足直播的需求。关于直播的带宽大小和流量消耗的计算同…

记录一次抓取WiFi驱动日志以及sniffer日志

起因 路由器桥接一个WiFi&#xff0c;然后设备连接这个路由器的WiFi&#xff0c;发现网络不可用&#xff0c;而手机或者电脑连接就没问题&#xff0c;与供应商沟通问题&#xff0c;需要抓取日志&#xff0c;记录一下 抓取WLAN DRIVER WLAN FW3日志 进入开发者模式打开启动WL…

hive常用方法

日期类 Date_sub 日期进行加减 &#xff0c;正的减&#xff0c;负的加 select current_date -- 当前日期,date_sub(current_date,1) -- 前一日,date_sub(current_date,-1) -- 后一日 from edw.test;字符类 split 该函数是分割字符串 &#xff0c;按照…

2023 年中国大学生计算机设计大赛上海决赛区正式开启!

中国大学生计算机设计大赛&#xff08;下文简称“大赛”&#xff09;是由教育部认证、我国高校面向本科生最早的赛事之一&#xff0c;自 2008 年开赛起&#xff0c;至今已是第十六届。大赛属于全国普通高校大学生竞赛排行榜榜单赛事&#xff0c;由教育部高校与计算机相关的教指…

结构型模式 - 组合模式

概述 对于这个图片肯定会非常熟悉&#xff0c;上图我们可以看做是一个文件系统&#xff0c;对于这样的结构我们称之为树形结构。在树形结构中可以通过调用某个方法来遍历整个树&#xff0c;当我们找到某个叶子节点后&#xff0c;就可以对叶子节点进行相关的操作。可以将这颗树理…

MySql 优化实例:修改 cross join 方式为子查询方式,以求改变执行计划

MySql 优化实例:修改 cross join 方式为子查询方式,以求改变执行计划 问题来源问题的追溯尝试使用索引排除日志表,验证查询速度变形查询指令修改程序中的调用指令对原有查询条件进行位置调整事后总结in 的使用初学者建议执行计划问题来源 问题内容出自问答:https://ask.cs…

【Hydro】HBV-light模型介绍及下载

HBV-light模型 HBV模型是一种模拟流域径流的半分布式水文模型。 什么是HBV-light&#xff1f; HBV模型软件除了原版&#xff08;版本由S. Bergstrm1976年开发&#xff09;之外还有很多不同版本。HBV-light在其先前版本中已在乌普萨拉大学开发&#xff08;并在俄勒冈州州立大…

业务开发“银弹” ——低代码开发平台

一、现状 低代码开发平台要让每个人&#xff0c;包括开发者和普通业务人员&#xff0c;都能够成为企业数字化过程中的主导者和构建者&#xff01;让普通人更容易上手&#xff01; 基于这一目标&#xff0c;应用需求多的云服务商成为低代码投资的主要来源。一家云服务商如谷歌云…

性能测试需求分析怎么做?(中)

本系列文章我们为大家系统地介绍一下性能测试需求分析&#xff0c;让大家全面掌握性能测试的第一个环节。本系列文章将会从性能测试需求分析整体概述、性能测试需求分析内容、性能测试需求分析方法这三个方面进行展开。在&#xff08;上&#xff09;部分中&#xff0c;我们为大…

linux之Ubuntu系列(六)用户管理 终端命令 which 查看执行命令所在的位置

提示 /etc/passwd 是用于保存用户信息的文件 可以用cat 命令查看 cat /etc/passwd/usr/bin/passwd 是用于修改用户密码的 程序 &#xff0c;是程序 程序 &#xff0c; which 命令 可以查看执行命令所在的位置 # 输出 /bin/ls which ls # 输出 /usr/sbin/useradd which useradd…

安达发|某大厂使用APS计划排程真实成功案例

在很多群里、朋友圈、公众号上可以看到&#xff0c;很多精益咨询老师认为&#xff0c;不仅ERP不啥用&#xff0c;APS更是无聊之举&#xff0c;而且肯定是用不好的。但&#xff0c;事实上可能还真不是这样的。 一个深圳的客户&#xff0c;用了APS以后&#xff0c;不仅装配的齐套…

【AI绘画】AI绘画乐趣:稳定增强扩散技术展现

目录 前言一、Stable Diffusion是什么&#xff1f;二、安装stable-diffusion-webui1. python安装2. 下载模型3. 开始安装&#xff1a;4. 汉化&#xff1a;5. 模型使用&#xff1a;6. 下载新模型&#xff1a;7. 基础玩法 三、总结 前言 本文将借助stable-diffusion-webui项目来…

[sinlinx-v3s]mke2fs

简介 mke2fs命令是Linux中的一个磁盘格式化命令&#xff0c;用于创建一个新的ext2、ext3或ext4文件系统。它可以将一个分区或者一个整个磁盘设备格式化为ext2、ext3或ext4文件系统&#xff0c;以便在Linux系统中进行数据存储和管理。 mke2fs命令的作用是按照指定的文件系统类…

java项目之足球赛会管理系统(ssm+mysql+jsp)

风定落花生&#xff0c;歌声逐流水&#xff0c;大家好我是风歌&#xff0c;混迹在java圈的辛苦码农。今天要和大家聊的是一款基于ssm的足球赛会管理系统。技术交流和部署相关看文章末尾&#xff01; 项目地址&#xff1a; https://download.csdn.net/download/sinat_26552841…

RTL8380MI/RTL8382MI管理型交换机系统软件操作指南七:ERPS以太环网保护切换协议

ISW9010G-2GS和IKS9228G-4GC都支持ERPS(Ethernet Ring Protection Switching&#xff0c;以太环网保护切换协议)&#xff0c;首先对ERPS进行详细的描述&#xff0c;主要包括以下五大内容&#xff1a;ERPS概述、ERPS技术介绍、ERPS工作原理、全局配置、环网信息 1.1 ERPS概述 E…

【Java项目实战-牛客社区】--maven安装与配置

1.下载Maven 官网 2.配置MAVEN_HOME maven 的使用是在jdk的基础上&#xff0c;所以电脑必须有jdk 第一步&#xff1a;新增环境变量&#xff1a;MAVEN_HOME 第二步&#xff1a;在path环境变量中添加&#xff1a;%MAVEN_HOME%\bin 找到环境变量配置界面 第三步&#xff1a;测试…

出租屋智能电表系统

随着科技的不断发展&#xff0c;智能化逐渐成为人们生活中不可或缺的一部分。在房屋租赁市场中&#xff0c;智能电表系统成为越来越多出租屋的标配&#xff0c;为房东和租户带来了便捷和安全。本文将从以下几个方面介绍出租屋智能电表系统的特点和优势。 一、出租屋智能电表系统…

Redis入门基础命令

文章目录 一、redis1.1 redis概述1.2 redis安装 二、string2.1 基础命令2.2 存储结构2.3 应用 三、list3.1 基础命令3.2 应用 四、hash4.1 基础命令4.2 存储结构4.3 应用 五、set5.1 基础命令5.2 存储结构5.3 应用 六、zset6.1 基础命令6.2 存储结构6.3 应用 一、redis 1.1 re…

第四章Shell编程之正则表达式与文本处理器

文本处理有三剑客&#xff1a;grep sed awk 通配符&#xff1a;只能匹配文件名与目录名&#xff0c;不能匹配文件的内容 *匹配任意一个或者多个字符 &#xff1f;匹配任意一个字符&#xff08;就是匹配单个字符&#xff09; [ ] 匹配范围内的任意单个字符 正则表达式&…

通过机器学习提升APP开发:未来已来

机器学习是当今技术的核心&#xff0c;也是开发 APP的核心。机器学习可以帮助您解决许多 APP开发中的问题。对于那些想要让他们的产品更上一层楼的 APP开发人员来说&#xff0c;了解如何通过机器学习提升 APP开发&#xff0c;以获得更高的投资回报率&#xff0c;这可能会让他们…