打造自己的基金工具-基金净值信息

615 阅读3分钟

背景

续接上篇,VSCode的基金插件确实不错,不过盈亏查看用着感觉不对,多次购买同一基金后,基金持仓不会填了,而且我还想要更多的数据项,于是乎,自己倒腾个基金工具。

获取基金信息

获取基金的接口有很多,比如天天基金、腾讯、新浪以及其他证券金融公司网站。 这次我选择天天基金的接口,接口地址为:http://fundgz.1234567.com.cn/js/基金代码.js

接口测试:

GET http://fundgz.1234567.com.cn/js/012414.js HTTP/1.1

测试结果:

HTTP/1.1 200 OK
Last-Modified: Tue, 21 Dec 2021 06:53:19 GMT
Etag: "ed43c7037f6d71:0"
Server: NWS_TCloud_static_msoc2
Date: Tue, 21 Dec 2021 06:54:29 GMT
Expires: Tue, 21 Dec 2021 07:04:29 GMT
Content-Type: application/x-javascript
X-Powered-By: ASP.NET
X-Daa-Tunnel: hop_count=1
Cache-Control: max-age=600
Content-Length: 166
Accept-Ranges: bytes
X-NWS-LOG-UUID: 13644477591170197640
X-Cache-Lookup: Cache Hit
Connection: close
Age: 100

jsonpgz({"fundcode":"012414","name":"招商中证白酒指数(LOF)C","jzrq":"2021-12-20","dwjz":"1.3883","gsz":"1.3767","gszzl":"-0.84","gztime":"2021-12-21 14:50"});

接口返回了基金名称、基金单位净值、基金估值、涨跌幅等信息,因此借此可以封装一个获取基金信息的模块

基金信息获取模块

# coding : utf-8
import requests
import json
import sys


def get_info_fundgz(code, fund):
    """
    天天基金获取基金最新信息
    :param code: 基金代码
    :param fund: 目标基金对象
    :return: 无
    """
    try:
        # 获取信息
        url = 'http://fundgz.1234567.com.cn/js/{0}.js'.format(code)
        resp = requests.get(url)
        if resp.status_code != 200:
            return
        text = resp.text
        # 解析为JSON对象
        data = json.loads(text[8:-2])
        # 设置信息
        info = fund.info
        info["基金代码"] = data["fundcode"]
        info["基金名称"] = data["name"]
        info["日涨跌幅"] = data["gszzl"]
        info["净值估算"] = data["gsz"]
        info["净值日期"] = data["jzrq"]
        info["基金净值"] = data["dwjz"]
        info["更新时间"] = data["gztime"]
    except:
        pass


class FundInfo:
    """
    基金信息
    """

    def __init__(self, code):
        self.code = code
        # 基金代码 基金名称 日涨跌幅 净值估算 盈亏估算 更新时间 昨日净值 持仓市值 持仓成本 持仓份额 持仓盈亏
        self.info = {}

    def set_position_amount(self, price, amount):
        """
        设置基金持仓成本价及份额
        :param price: 持仓成本价
        :param amount: 持仓数量(份额)
        :return:
        """
        self.info['持仓成本'] = '{0:.4f}'.format(price)
        self.info['持仓份额'] = '{0:0.2f}'.format(amount)
        self.info['持仓金额'] = '{0:0.2f}'.format(price*amount)

    def set_position_cost(self, price, costs):
        """
        设置基金持仓成本价及份总成本
        :param price: 持仓成本价
        :param costs: 持仓金额
        :return:
        """
        self.info['持仓成本'] = '{0:.4f}'.format(price)
        self.info['持仓金额'] = '{0:0.2f}'.format(costs)
        self.info['持仓份额'] = '{0:0.2f}'.format(float(self.info['持仓金额'])/float(self.info['持仓成本']))

    def fresh(self):
        """
        重新获取基金信息,联网
        :return:
        """
        get_info_fundgz(self.code, self)
        try:
            if '持仓成本' not in self.info:
                self.info['持仓成本'] = '0.0000'
            if '持仓份额' not in self.info:
                self.info['持仓份额'] = '0.00'

            if float(self.info['持仓份额']) > 0.001 and self.info['基金净值'] != self.info['净值估算']:
                self.info['今日盈亏'] = '{0:.4f}'.format(float(self.info['持仓份额']) * (float(self.info['净值估算']) - float(self.info['基金净值'])))
            else:
                self.info['今日盈亏'] = '0.0000'

            self.info['持仓市值'] = '{0:.4f}'.format(float(self.info['持仓份额'])*float(self.info['基金净值']))
            if self.info['基金净值'] != self.info['持仓成本']:
                self.info['持仓盈亏'] = '{0:.4f}'.format(float(self.info['持仓份额']) * (float(self.info['基金净值']) - float(self.info['持仓成本'])))
            else:
                self.info['持仓盈亏'] = '0.0000'
            if float(self.info['持仓份额']) > 0.001:
                self.info['总收益率'] = '{0:.4f}'.format(100.0 * (float(self.info['基金净值']) - float(self.info['持仓成本'])) / float(self.info['持仓成本']))
            else:
                self.info['总收益率'] = '0.0000'

            self.info['总盈亏估算'] = '{0:.4f}'.format(float(self.info['今日盈亏']) + float(self.info['持仓盈亏']))
            self.info['收益率估算'] = '{0:.4f}'.format(float(self.info['总盈亏估算'])*100/float(self.info['持仓金额']))
        except:
            pass

    @staticmethod
    def get_info_with_amount(code, price, amount):
        fund = FundInfo(code)
        fund.set_position_amount(price, amount)
        fund.fresh()
        return fund

    @staticmethod
    def get_info_with_cost(code, price, cost):
        fund = FundInfo(code)
        fund.set_position_cost(price, cost)
        fund.fresh()
        return fund


def json_dumps(info):
    """
    字典转化为JSON并格式化
    :param info:
    :return:
    """
    return json.dumps(info, ensure_ascii=False, indent=4)


if __name__ == '__main__':
    argv = sys.argv
    # 测试运行
    if len(argv) < 2:
        # 持仓成本价+持仓总份额
        fund = FundInfo.get_info_with_amount('006229', 0, 0.00)
        # 持仓成本价+买入总成本
        #fund = FundInfo.get_info_with_cost('006229', 2.4514, 25000)
    # 带命令行启动
    else:
        argv[1] = "FundInfo.get_info_with_cost('006228', 2.4515, 25000)"
        fund = eval(argv[1])
    result = json_dumps(fund.info)
    print(result)

测试执行结果

D:\Study\fund>python fund_info.py
{
    "持仓成本": "0.0000",
    "持仓份额": "0.00",
    "持仓金额": "0.00",
    "基金代码": "006229",
    "基金名称": "中欧医疗创新股票C",
    "日涨跌幅": "1.80",
    "净值估算": "2.2735",
    "净值日期": "2021-12-20",
    "基金净值": "2.2333",
    "更新时间": "2021-12-21 14:58",
    "今日盈亏": "0.0000",
    "持仓市值": "0.0000",
    "持仓盈亏": "0.0000",
    "总收益率": "0.0000",
    "总盈亏估算": "0.0000"
}

收工,下次再包装一下,形成一个可以用的产品...(未完待续)