vlambda博客
学习文章列表

同花顺爱基金量化自动交易,重磅图像验证码识别

本人金融大学生一枚,喜欢将金融和编程结合,分析问题,喜欢的点赞关注,我会一直去学习,分享文章,因为毕竟目前了解,学习的还是太少。我们可以利用同花顺爱基金进行自动化交易,其他基金我没有账号,同花顺也很好,我们可以利用浏览器自动化交易,配合我们的量化交易策略,因为基金一般适合长期,所以我们一般一天交易一次,没有触发量化交易不进行交易,我们将交易时间设为交易日的下午2点到3点,其他时间运行程序,不会进行交易,在交易中有一个登录难点就是图像验证码的识别,输入,如果是手动输入那就没有这个难点,但是我们还是希望让程序进行自动识别图像验证码,我们借用ddddocr,PIL进行图片的处理,我们利用senlenium启动浏览器进行交易,我们的验证码识别的思想是利用程序进行自动截图,保存截图照片,找到验证码的属性,比如位置,大小,如果有时间我会写一篇验证码识别的文章,现在在仔细研究一下验证码识别,我们的交易策略为5日均线策略

我们看一下验证码属性

图像识别代码

同花顺爱基金量化自动交易,重磅图像验证码识别

在基金交易中没有当天的实时数据,我们爬取东方财富基金估值数据做为基金今天的数据,东方财富基金实时估值数据,随便选择一个

同花顺爱基金量化自动交易,重磅图像验证码识别

我们运行程序输入帐号,登录密码,交易密码,交易的基金代码比如005939

程序效果

同花顺爱基金量化自动交易,重磅图像验证码识别

同花顺爱基金量化自动交易,重磅图像验证码识别

同花顺爱基金量化自动交易,重磅图像验证码识别

我们可以看到程序运行输入了验证码,验证码程序结果,和保存下来的图片

同花顺爱基金量化自动交易,重磅图像验证码识别

同花顺爱基金量化自动交易,重磅图像验证码识别

同花顺爱基金量化自动交易,重磅图像验证码识别

同花顺爱基金量化自动交易,重磅图像验证码识别

这个为保存下来的数据

同花顺爱基金量化自动交易,重磅图像验证码识别

我们登录进去就可以交易了

程序代码

#利用同花顺基金进行基金实盘交易

#交易策略为均线策略,大跌补仓,大涨减仓

#可用看,谨慎使用,一般不尝试,

#条件符合程序会运行,而且速度特别快

import pandas as pd

from finta import TA

from selenium  import webdriver

from selenium import common

import akshare as ak

import requests

from bs4 import BeautifulSoup

from lxml import etree

import time

import pyautogui

import matplotlib.pyplot as plt

import PySimpleGUI as sg

import ddddocr

import pytesseract

from  PIL import Image,ImageDraw,ImageFont

code=sg.popup_get_file('输入基金代码比如006939')

zh=sg.popup_get_file('输入交易账号一般为身份证号')

dl=sg.popup_get_file('输入同花顺基金登录密码')

passworld=sg.popup_get_file('输入爱基金交易密码')

driver=webdriver.Firefox()

#登录同花顺a

def log():

    '''

    登录程序

    '''

    #启动火狐浏览器

    driver.get('https://trade.5ifund.com/login/login/loginInit.action?referrer=https%3A%2F%2Ftrade.5ifund.com%2Fpc%2Findex.html%3Fa%3D3%26frm%3Dijijin')

    #最大化窗口

    driver.maximize_window()

    #登录账号

    driver.find_element_by_xpath('//*[@id="cardOrCustId"]').clear()

    #账号

    driver.find_element_by_xpath('//*[@id="cardOrCustId"]').send_keys(zh)

    #交易密码

    driver.find_element_by_xpath('//*[@id="tradePassword"]').clear()

    driver.find_element_by_xpath('//*[@id="tradePassword"]').send_keys(dl)

#图像验证码识别

def image_ocr():

    '''

    识别图像验证码,登录

    如果采用手动输入验证码,可以不调用这个验证码识别函数

    '''

    #截屏保存为图片

    driver.save_screenshot(r'C:\Users\Administrator\Desktop\图片.png')

    #找到验证码图片属性

    pin=driver.find_element_by_xpath('//*[@id="validateCode"]')

    #左位置

    left=pin.location['x']

    #距离顶图的位置

    top=pin.location['y']

    right=left+pin.size['width']

    height=top+pin.size['height']

    #打开保存图片

    img=Image.open(r'C:\Users\Administrator\Desktop\图片.png')

    #抠出验证码照片

    #因为我们电脑显示的是按1.25比例显示的所以我们的值都应该乘1.25

    im=img.crop((left*1.25,top*1.25,right*1.25,height*1.25))

    #保存为验证码

    im.save(r'C:\Users\Administrator\Desktop\验证码.png')

    #识别验证码

    ocr=ddddocr.DdddOcr()

    with open(r'C:\Users\Administrator\Desktop\验证码.png','rb'as f:

        imag=f.read()

    result=ocr.classification(imag)

    print('验证码结果',result)

    #输入验证码

    driver.find_element_by_xpath('//*[@id="rand"]').clear()

    time.sleep(1)

    #输入验证码

    driver.find_element_by_xpath('//*[@id="rand"]').send_keys(result)

    time.sleep(1)

    #登录

    driver.find_element_by_xpath('//*[@id="loginIN"]').click()

    print('登录成功')

#定义交易函数

def buy(stock=code,money=100,passworld=passworld):

    '''

    stock是基金代码,money是购买基金金额,passworld是交易密码

    '''

    #点击购买基金

    driver.find_element_by_xpath('/html/body/div[1]/h2/a[2]').click()

    #输入基金代码比如005939工银新能源汽车

    driver.find_element_by_xpath('//*[@id="fc_autocomplete"]').send_keys(stock)

    driver.find_element_by_xpath('//*[@id="fc_autocomplete"]').click()

    time.sleep(2)

    #点击购买

    driver.find_element_by_xpath('//*[@id="fc_buy"]').click()

    time.sleep(2)

    #购买金额

    driver.find_element_by_xpath('//*[@id="amount_money"]').send_keys(money)

    time.sleep(2)

    #下一步

    driver.find_element_by_xpath('//*[@id="nextpage"]').click()

    time.sleep(2)

    #交易密码

    driver.find_element_by_xpath('//*[@id="buy_tradePassword"]').send_keys(passworld)

    time.sleep(2)

    #付款

    driver.find_element_by_xpath('//*[@id="dosubmit"]').click()

    time.sleep(2)

    print('付款成功,买入成功')

#基金定投函数,当市场行情差,我们选择定投

#进入定投

def auto_trade(stock='005939',money=100,passworld=passworld):

    '''

    stock是基金代码,money是定投金额,passworld是交易密码

    '''

    #定投

    driver.find_element_by_xpath('/html/body/div[1]/h2/a[5]').click()

    #定投基金代码

    driver.find_element_by_xpath('//*[@id="dt_autocomplete"]').send_keys(stock)

    #点击定投

    driver.find_element_by_xpath('//*[@id="dt_buy"]').click()

    #我们选择银行卡的方式进行定投,每月1日定投一次

    driver.find_element_by_xpath('//*[@id="dayofdate"]').click()

    #选择日期

    pyautogui.click(x=515,y=614)

    #定投金额

    driver.find_element_by_xpath('//*[@id="amount"]').send_keys(money)

    #下一步

    driver.find_element_by_xpath('//*[@id="nextpage"]').click('//*[@id="p2_tradePassword"]')

    #输入交易密码

    driver.find_element_by_xpath('//*[@id="p2_tradePassword"]').send_keys(passworld)

#同花顺钱包充值函数

def fill_money(money=100,passworld='111111'):

    #回到主界面,我的基金

    driver.find_element_by_xpath('/html/body/div[1]/h2/a[1]').click()

    #充值

    driver.find_element_by_xpath('/html/body/div[2]/div[1]/div[3]/div[1]/dl/dd/span[3]/a[1]').click()

    #充值金额

    driver.find_element_by_xpath('//*[@id="amount_money"]').send_keys(money)

    #下一步

    driver.find_element_by_xpath('//*[@id="nextpage"]').click()

    #交易密码

    driver.find_element_by_xpath('//*[@id="buy_tradePassword"]').click()

    #付款

    driver.find_element_by_xpath('//*[@id="buy_tradePassword"]').click()

    print('充值完成')

    driver.refresh()

#基金赎回函数,基金的卖出

def sell(n=1,fe=100,passworld=passworld):

    '''

    n选择赎回第几个基金,fe赎回份儿,passworld交易密码

    '''

    #回到界面我的基金

    driver.find_element_by_xpath('/html/body/div[1]/h2/a[1]').click()

    #选择赎回第几个持有基金,如果是一个默认输入

    driver.find_element_by_xpath('/html/body/div[2]/div[1]/div[3]/div[4]/div[1]/div[{}]/span/a[1]'.format(n))

    #检测可以赎回的份额

    kyfe=driver.find_element_by_xpath('//*[@id="p_totalUsableVolText"]').text

    if float(kyfe[:5])>0 and fe<=float(kyfe[:5]):

        print('可用份额充足,还有{}份额'.format(float(kyfe[:5]-fe)))

        #输入赎回份额

        driver.find_element_by_xpath('//*[@id="money"]').send_keys(fe)

        #下一步

        driver.find_element_by_xpath('//*[@id="nextpage"]').click()

        #输入交易密码

        driver.find_element_by_xpath('//*[@id="redeem_tradePassword"]').send_keys(passworld)

        #赎回成功

        driver.find_element_by_xpath('//*[@id="dosubmit"]').click()

        print('赎回成功')

        driver.refresh()

    else:

        print('赎回失败,份额不足')

#基金转换函数

def change(n=1,fe=100,passworld=passworld):

    #回到主界面,我的基金

    driver.find_element_by_xpath('/html/body/div[1]/h2/a[1]').click()

    #基金转换,默认转换第一个持有的基金也可用选择

    driver.find_element_by_xpath('/html/body/div[2]/div[1]/div[3]/div[4]/div[{}]/div[1]/span/a[2]'.format(n)).click()

    #检测可用转换的基金份额

    kyfe=driver.find_element_by_xpath('//*[@id="p_totalUsableVolText"]').text

    if float(kyfe[:-1])>0 and float(kyfe[:-1])>fe:

        print('可用份额充足,还有{}'.format(float(kyfe[:-1])-fe))

        #输入转换份额

        driver.find_element_by_xpath('//*[@id="money"]').send_keys(fe)

        #默认转入可用转入的第一个基金

        driver.find_element_by_xpath('/html/body/div[2]/div[1]/div/form/dl[2]/dd[1]/select/option[2]').click()

        #下一步

        driver.find_element_by_xpath('//*[@id="nextpage"]').click()

        #交易密码

        driver.find_element_by_xpath('//*[@id="convert_tradePassword"]').send_keys(passworld)

        #转换完成

        driver.find_element_by_xpath('//*[@id="dosubmit"]').click()

        print('基金转换成功')

    else:

        print('转换失败,份儿不足,没有可用转换的基金')

        driver.refresh()

#同花顺钱包提现函数

def close_money(money=100,passworld=passworld):

    #会到主界面

    driver.find_element_by_xpath('/html/body/div[1]/h2/a[1]').click()

    #提现

    driver.find_element_by_xpath('/html/body/div[2]/div[1]/div[3]/div[1]/dl/dd/span[3]/a[2]').click()

    #检测是否有钱提现

    cash=driver.find_element_by_xpath('//*[@id="sumAvailablevol"]').text

    if float(cash)>0 and float(cash)<money:

        print('金额充足,可用提现')

        #输入提现金额,默认100

        driver.find_element_by_xpath('//*[@id="money"]').send_keys(money)

        #输入交易密码

        driver.find_element_by_xpath('//*[@id="buy_tradePassword"]').send_keys(passworld)

        #提现成功

        driver.find_element_by_xpath('//*[@id="dosubmit"]').click()

        print('提现成功')

    else:

        print('提现失败,可用提现的资金不足')

#写交易策略均线策略,基金数据一般晚上9点半数据更新完成,所以今天的数据我们爬取天天基金的基金估值数据

while True:

    date=time.localtime()

    #年

    year=date.tm_year

    #月

    mon=date.tm_mon

    #日

    day=date.tm_mday

    #小时

    hour=date.tm_hour

    #星期

    wday=date.tm_wday

    #现在的时间

    now_time=('{}-0{}-{}'.format(year,mon,day))

    now_times=[]

    now_times.append(now_time)

    #交易日运行该函数下午2点到3点运行程序

    if hour>=9 and hour>15:

        log()

        #验证码识别输入

        image_ocr()

        print('运行程序')

        #单位净值

        res=requests.get('http://fund.eastmoney.com/{}.html?spm=search'.format(code))

        df=etree.HTML(res.text)

        dwjz=(''.join(df.xpath('//*[@id="body"]/div[11]/div/div/div[3]/div[1]/div[1]/dl[2]/dd[1]/span[1]/text()')).strip())

        dwjzs=[]

        dwjzs.append(str(dwjz))

        #涨跌幅

        zf=(''.join(df.xpath('//*[@id="body"]/div[11]/div/div/div[3]/div[1]/div[1]/dl[2]/dd[1]/span[2]/text()')).strip())

        if zf[0]=='-':

            zdf=str(zf[:-1])

        else:

            zdf=str(zf[:-1])

        zdfs=[]

        zdfs.append(zdf)

        #实时净值估算

        jzgs=(''.join(df.xpath('//*[@id="gz_gszzl"]/text()')).strip())

        jzgss=[]

        jzgss.append(jzgs)

        df1=ak.fund_open_fund_info_em(fund=code)

        df2=df1

        df2['ma5']=df2['单位净值'].rolling(window=5).mean()

        df2['ma10']=df2['单位净值'].rolling(window=10).mean()

        df2.to_excel(r'C:\Users\Administrator\Desktop\基金实盘.xlsx')

        #交易策略5日均线,10日均线

        #均线金叉买入

        if float(df2['ma5'].tolist()[-2])<float(df2['ma10'].tolist()[-2]):

            if float(df2['ma5'].tolist()[-1])>float(df2['ma10'].tolist()[-1]):

                buy()

                print('金叉买入成功')

        #均线死叉卖出

        if float(df2['ma5'].tolist()[-2])>float(df2['ma10'].tolist()[-2]):

            if float(df2['ma5'].tolist()[-1])<float(df2['ma10'].tolist()[-1]):

                sell(passworld=passworld)

                print('死叉卖出成功')

        #大跌补仓,我们一般认为大跌为3%,买进

        if float(df2['日增长率'].tolist()[-1])<=-3:

            buy(stock=code,passworld=passworld)

            print('大跌补仓成功')

        #大涨减仓,一般认为当时上涨大于3%

        if float(df2['日增长率'].tolist()[-1])>=3:

            sell(passworld=passworld)

            print('大涨补仓成功')

    #下个月开始定投,设置一次就好

    if mon==2 and day==28:

        auto_trade(stock=code,passworld=passworld)

        print('开始定投,定投成功')

    #上升趋势买进不写,因为没有钱

    #下降趋势也是

    #月底绘制基金走势图

    if day==28:

        plt.rcParams['font.family']='SimHei'

        #显示负数

        plt.rcParams['axes.unicode_minus']=False

        plt.plot(df2['净值日期'],df['单位净值'],label='单位净值走势',color='m')

        plt.plot(df2['净值日期'],df['ma5'],label='5日均线',color='r')

        plt.plot(df2['净值日期'],df['ma10'],label='10日均线',color='g')

        plt.legend()

        plt.pause(0.1)

    #程序间隔1小时运行一次,一天符合条件交易一次

    else:

        print('不是交易时间等待交易')

        time.sleep(3600)