商品期货基本面分析交易方法

论坛 期权论坛 期权     
宽客在线   2020-12-26 23:18   9102   0


发明者 - 筑就非凡的量化世界

注:本文策略依托于发明者量化(FMZ.COM)
摘要在期货交易市场,无论是私募机构还是普通散户,争论技术分析和基本面分析谁好谁坏,从来就没有停止过。


技术分析者认为价格已经包含了一切,相信未来价格还以趋势方式演变,只关心图表上价格行为本身的变化,判断它能卖多少钱。


基本面分析者认为真正价值最终将会反映在价格上,并不需要关心短期价格走势,更多的是分析影响价格背后的因素,判断它值多少钱。






1基本面分析的难点
之前听过这样一句话:“散户可以完全无视基本面分析,只需要关注技术分析即可。”当时不以为然,但随着时间的推移,和大量实盘的磨砺,现在回过头看,也渐渐接受了这种观点。


因为传统的基本面分析相对于散户来说,门槛真的很高,想要分析某些事合力后会发生什么结果,最起码获取与之关联的数据是全面的、准确的。否则,再怎么分析,也只是片面的。


影响期货基本面分析的因素
  • 宏观
    • 宏观政策
    • 产业政策
    • 政治因素
    • 外汇汇率
    • 经济周期
    • 货币政策
  • 品种
    • 升水贴水
    • 供需关系
    • 商品库存
    • 产业利润
  • 其他
    • 季节因素
    • 天气因素
    • 新闻事件
    • 市场情绪


如上面这个列表,与商品期货基本面分析有关的三大因素,林林总总多达数十项,往细了分,更有几十项之多,并且这些数据是在不停变化的。单个散户想要获取这些庞大的数据已经是力所不及的事了,更不用提客观分析。


所以从这一点来讲,在机构和散户共存的市场中,散户在起跑线上就已经处于劣势中。尽管机构也不是近乎完美,但相对于散户,有更多的优势去获取更多更准确的信息,以及素质更高的分析团队。所以,在只论输赢的交易市场,散户的赢面很小。那么有没有合适散户的基本面分析法呢?






2期货基本分析的核心
其实,期货的基本面分析并不是想象中那么难,只需要抓住基本面分析核心要素,就能剥丝抽茧从错综复杂的信息中找出规律。我们知道影响商品期货的三大因素中包括:宏观、品种、其他。


宏观经济数据复杂多变,每天每时每刻,地球上有太多的经济数据公布,各国政界、央行、投行,官方的和非官方的。除了政治和经济危机外,宏观分析是聊天的好材料,实用性不大。美国著名的基金管理专家彼得·林奇曾发表看法:“我每年花在经济大势上的分析时间不超出十五分钟”。


另外,在季节因素、天气因素、新闻事件、市场情绪中,很多都是突发事件,本身就是无法分析预测的。所以散户只需要把精力放在品种上即可,因为期货和现货的价格都是公开的,可以计算出升水还是贴水。现货的库存数据在一些网站还是比较容易获取的,可以预判出相对的供需关系等等,从而判断期货未来的大概价值。


升水贴水



同样一个商品品种,在现货市场与期货市场的价格差,叫做基差。如果期货价格大于现货价格,我们称之为期货升水;如果期货价格小于现货价格,我们称之为期货贴水。


无论是升水还是贴水,随着交割日期的临近,现货价格与期货价格都会趋于一致,一种是期货向现货回归,另一种是现货向期货回归。从期货市场很难判断基差究竟会以哪种方式回归,所以只能从现货市场中寻找蛛丝马迹。


供需关系
影响商品现货价格的因素虽然有很多,但最终大都体现在供需关系上。如果买者多于卖者,价格就会上涨;如果卖者多于买者,价格就会下跌。国内的商品期货大致上可以分为:农产品和工业品。


期货圈子中流传着这样一句话:“农产品看供给,工业品看需求。”农产品是刚需,需求是相对稳定的,决定价格主要看供给;工业品是下游需求带动的,再者国内基本都产能过剩,决定价格主要看需求。



虽然,在实际操作中我们很难获取工业品的需求数据,也很难计算出农产品的供给数据。但是价格波动依存于供给与需求的相互作用,这种相互作用的结果就是库存。


如果库存处于低位,说明市场供不应求,需求的力量大于供给的力量,未来价格看涨;如果库存处于高位,说明市场供大于求,供给的力量大于需求的力量,未来价格看跌。


仓单
所谓的仓单就是交易所的交割仓库入库现货后开具的标准仓单,它反映的是交易所公布的库存数量。当期货价格较高时,现货商就是注册仓单然后在市场上销售,所以根据这个原理我们可以反推出在期货中的交易方向。
  • 期货多头:如果仓单大量减少,说明期货价格低于现货价格,应该做多。
  • 期货空头:如果仓单大量增加,说明期货价格高于现货价格,应该做空。
另外,还可以利用仓单来判断库存。仓单既可以注册也可以注销,当期货主力想要价格上涨时,会把持有的注册仓单注销掉,改变交易所公布的库存数量,来达到交割货物不足的假象,进而影响期货价格上涨的预期。当期货主力想要价格下跌时,会注册仓单,造成交割货物增多的假象,使得被动影响期货价格下跌。


到这里,基本面分析三大因素:库存、基差、仓单就已经凑齐了,有些做基本面分析的朋友可能还会加上产业利润、技术分析等等,增加窥视市场的维度,理论上两者相加是大于二的,因为能知道越多信息,越多的角度去观察市场,才能做出更好的决策。那么我们的基本面交易策略可以为一下条件:
  • 多头:贴水 + 低库存 + 仓单减少
  • 空头:升水 + 高库存 + 仓单增加






3获取数据
接下来,我们就利用发明者量化交易平台,来获取这些数据吧!
  1. '''backtest
复制代码
  1. start: 2019-01-01 00:00:00
复制代码
  1. end: 2019-08-09 00:00:00
复制代码
  1. period: 1d
复制代码
  1. exchanges: [{"eid":"Futures_CTP","currency":"FUTURES"}]
复制代码
  1. '''
复制代码
复制代码
复制代码
  1. # 导入库
复制代码
  1. import requests
复制代码
  1. import re
复制代码
  1. from bs4 import BeautifulSoup
复制代码
  1. import time
复制代码
  1. import datetime
复制代码
  1. import random
复制代码
  1. import json
复制代码
  1. import threading
复制代码
复制代码
复制代码
  1. # 请求头文件
复制代码
  1. request_headers = {
复制代码
  1.     'Connection': 'keep-alive',
复制代码
  1.     'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9',
复制代码
  1.     'accept-language': 'zh-CN,zh;q=0.9,en;q=0.8',
复制代码
  1.     'accept-encoding': 'gzip, deflate',
复制代码
  1.     'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.132 Safari/537.36',
复制代码
  1.     'Referer': 'http://www.100ppi.com/sf2/day-2019-01-02.html'
复制代码
  1. }
复制代码
复制代码
复制代码
  1. # ip代理
复制代码
  1. proxies = {
复制代码
  1.     'http': 'http://182.35.82.128:9999', 'https': 'https://182.35.82.128:9999'
复制代码
  1. }
复制代码
复制代码
复制代码
  1. # 全局变量
复制代码
  1. diff_data = 0  # 存储基差数据
复制代码
  1. reserve_data = 0  # 存储库存数据
复制代码
  1. receipt_data = 0  # 存储仓单数据
复制代码
  1. profit_data = 0  # 存储虚拟利润数据
复制代码
复制代码
复制代码
  1. # 日期转时间戳
复制代码
  1. def to_timestamp(date_str):
复制代码
  1.     times = date_str + " 00:00:00"
复制代码
  1.     time_array = time.strptime(times, "%Y-%m-%d %H:%M:%S")
复制代码
  1.     return int(round(time.mktime(time_array) * 1000))
复制代码
复制代码
复制代码
  1. # 返回日期数组
复制代码
  1. def date_arr(year, month, day):
复制代码
  1.     begin = datetime.date(year, month, day)
复制代码
  1.     end = datetime.date.today()
复制代码
  1.     arr = []
复制代码
  1.     for i in range((end - begin).days + 1):
复制代码
  1.         day = begin + datetime.timedelta(days=i)
复制代码
  1.         arr.append([str(day).replace('-', ''), str(day),
复制代码
  1.                     day.weekday() + 1, to_timestamp(str(day))])
复制代码
  1.     return arr
复制代码
复制代码
复制代码
  1. # 获取基差
复制代码
  1. def spot_futures_diff_data(date, futures_name):
复制代码
  1.     global diff_data
复制代码
  1.     url = f"http://www.100ppi.com/sf2/day-{date}.html"  # 获取生意社的基差数据
复制代码
  1.     try:
复制代码
  1.         url_text = requests.get(
复制代码
  1.             url, headers=request_headers).text
复制代码
  1.     except BaseException:
复制代码
  1.         Log('获取基差数据失败')
复制代码
  1.         return int(diff_data)
复制代码
  1.     soup = BeautifulSoup(url_text, "html5lib")
复制代码
  1.     if len(soup.select("#fdata")) > 0:
复制代码
  1.         results = soup.select("#fdata")[0]
复制代码
  1.         for i in results.find_all('tr'):
复制代码
  1.             if len(i.find_all('td', text=futures_name)) > 0:
复制代码
  1.                 data = i.find_all('font')[0].text
复制代码
  1.                 if data is not None:
复制代码
  1.                     diff_data = data
复制代码
  1.     return int(diff_data)
复制代码
复制代码
复制代码
  1. # 获取库存
复制代码
  1. def spot_reserve_data(date, futures_name):
复制代码
  1.     global reserve_data
复制代码
  1.     # 获取上期所的库存数据
复制代码
  1.     url = f'http://www.shfe.com.cn/data/dailydata/{date}weeklystock.dat'
复制代码
  1.     try:
复制代码
  1.         url_text = requests.get(url, headers=request_headers).text
复制代码
  1.     except BaseException:
复制代码
  1.         print('获取库存数据失败')
复制代码
  1.         return reserve_data
复制代码
  1.     total = 0
复制代码
  1.     count = 0
复制代码
  1.     if url_text[0] == '{':
复制代码
  1.         for i in json.loads(url_text)['o_cursor']:
复制代码
  1.             if futures_name in i['VARNAME']:
复制代码
  1.                 if '合计' not in i['WHABBRNAME'] and '总计' not in i['WHABBRNAME']:
复制代码
  1.                     try:
复制代码
  1.                         inventory = int(i['WHSTOCKS'])
复制代码
  1.                     except BaseException:
复制代码
  1.                         return reserve_data
复制代码
  1.                     if inventory > 0:
复制代码
  1.                         total = total + inventory
复制代码
  1.                         count = count + 1
复制代码
  1.         if count > 0:
复制代码
  1.             reserve_data = int(total / count)
复制代码
  1.     return reserve_data
复制代码
复制代码
复制代码
  1. # 获取仓单
复制代码
  1. def spot_receipt_data(date, futures_name):
复制代码
  1.     global receipt_data
复制代码
  1.     # 获取上期所的仓单数据
复制代码
  1.     url = f'http://www.shfe.com.cn/data/dailydata/{date}dailystock.dat'
复制代码
  1.     try:
复制代码
  1.         url_text = requests.get(url, headers=request_headers).text
复制代码
  1.     except BaseException:
复制代码
  1.         print('获取库存数据失败')
复制代码
  1.         return receipt_data
复制代码
  1.     total = 0
复制代码
  1.     count = 0
复制代码
  1.     if url_text[0] == '{':
复制代码
  1.         for i in json.loads(url_text)['o_cursor']:
复制代码
  1.             if futures_name in i['VARNAME']:
复制代码
  1.                 if '合计' not in i['WHABBRNAME'] and '总计' not in i['WHABBRNAME']:
复制代码
  1.                     try:
复制代码
  1.                         inventory = int(i['WRTWGHTS'])
复制代码
  1.                     except BaseException:
复制代码
  1.                         return receipt_data
复制代码
  1.                     if inventory > 0:
复制代码
  1.                         total = total + inventory
复制代码
  1.                         count = count + 1
复制代码
  1.         if count > 0:
复制代码
  1.             receipt_data = int(total / count)
复制代码
  1.     return receipt_data
复制代码
复制代码
复制代码
  1. # 虚拟利润
复制代码
  1. def get_profit_data():
复制代码
  1.     global profit_data
复制代码
  1.     profit_data = profit_data + random.randint(-100, 150)
复制代码
  1.     return profit_data
复制代码
复制代码
复制代码
  1. # 程序入口
复制代码
  1. def main():
复制代码
  1.     # threading.Thread(target=spot_futures_diff_arr, args=('天然橡胶',)).start()
复制代码
  1.     # threading.Thread(target=commodity_inventory_arr, args=('天然橡胶',)).start()
复制代码
  1.     # threading.Thread(target=commodity_warehouse_receipt_arr, args=('天然橡胶',)).start()
复制代码
复制代码
  1.     # 基差图表
复制代码
  1.     cfgA = {
复制代码
  1.         "extension": {
复制代码
  1.             "layout": 'single',
复制代码
  1.             "col": 6,
复制代码
  1.             "height": "500px",
复制代码
  1.         },
复制代码
  1.         "title": {
复制代码
  1.             "text": "基差图表"
复制代码
  1.         },
复制代码
  1.         "xAxis": {
复制代码
  1.             "type": "datetime"
复制代码
  1.         },
复制代码
  1.         "series": [{
复制代码
  1.             "name": "基差",
复制代码
  1.             "data": [],
复制代码
  1.         }]
复制代码
  1.     }
复制代码
复制代码
  1.     # 库存图表
复制代码
  1.     cfgB = {
复制代码
  1.         "extension": {
复制代码
  1.             "layout": 'single',
复制代码
  1.             "col": 6,
复制代码
  1.             "height": "500px",
复制代码
  1.         },
复制代码
  1.         "title": {
复制代码
  1.             "text": "库存图表"
复制代码
  1.         },
复制代码
  1.         "xAxis": {
复制代码
  1.             "type": "datetime"
复制代码
  1.         },
复制代码
  1.         "series": [{
复制代码
  1.             "name": "库存",
复制代码
  1.             "data": [],
复制代码
  1.         }]
复制代码
  1.     }
复制代码
复制代码
  1.     # 仓单图表
复制代码
  1.     cfgC = {
复制代码
  1.         "extension": {
复制代码
  1.             "layout": 'single',
复制代码
  1.             "col": 6,
复制代码
  1.             "height": "500px",
复制代码
  1.         },
复制代码
  1.         "title": {
复制代码
  1.             "text": "仓单图表"
复制代码
  1.         },
复制代码
  1.         "xAxis": {
复制代码
  1.             "type": "datetime"
复制代码
  1.         },
复制代码
  1.         "series": [{
复制代码
  1.             "name": "仓单",
复制代码
  1.             "data": [],
复制代码
  1.         }]
复制代码
  1.     }
复制代码
复制代码
  1.     # 虚拟利润图表
复制代码
  1.     cfgD = {
复制代码
  1.         "extension": {
复制代码
  1.             "layout": 'single',
复制代码
  1.             "col": 6,
复制代码
  1.             "height": "500px",
复制代码
  1.         },
复制代码
  1.         "title": {
复制代码
  1.             "text": "虚拟利润图表"
复制代码
  1.         },
复制代码
  1.         "xAxis": {
复制代码
  1.             "type": "datetime"
复制代码
  1.         },
复制代码
  1.         "series": [{
复制代码
  1.             "name": "利润",
复制代码
  1.             "data": [],
复制代码
  1.         }]
复制代码
  1.     }
复制代码
  1.     LogReset()  # 清除日志
复制代码
  1.     chart = Chart([cfgA, cfgB, cfgC, cfgD])  # 创建图表
复制代码
  1.     chart.reset()  # 初始清空图表
复制代码
  1.     for i in date_arr(2018, 1, 1):  # 从2018年1月1日开始获取历史数据
复制代码
  1.         diff = spot_futures_diff_data(i[1], '天然橡胶')  # 获取基差数据
复制代码
  1.         reserve = spot_reserve_data(i[0], '天然橡胶')  # 获取库存数据
复制代码
  1.         receipt = spot_receipt_data(i[0], '天然橡胶')  # 获取仓单数据
复制代码
  1.         profit = get_profit_data()  # 虚拟利润
复制代码
  1.         if diff != 0 and reserve != 0 and receipt != 0:  # 如果所有的数据都不为0
复制代码
  1.             chart.add(0, [i[3], diff])  # 绘制基差数据
复制代码
  1.             chart.add(1, [i[3], reserve])  # 绘制库存数据
复制代码
  1.             chart.add(2, [i[3], receipt])  # 绘制仓单数据
复制代码
  1.             chart.add(3, [i[3], profit])  # 绘制虚拟利润数据
复制代码
  1.             chart.update([cfgA, cfgB, cfgC, cfgD])  # 重置图表配置
复制代码
  1.             time.sleep(1)  # 休眠1秒
复制代码
  1.             Log(f'基差:{diff} 库存:{reserve} 仓单:{receipt} 日期:{i[1]}')  # 输出信息到日志
复制代码
完整的代码已经分享到发明者量化交易平台,可以直接复制策略无需设置,直接创建机器人即可:
https://www.fmz.com/strategy/161412






4实盘运行







5总结
字回到本篇的开场,基本面分析和技术分析并不存在孰优孰劣,它们探究的是同一个市场,只是站的角度不同。没有人可以仅凭一个角度分析,就能窥视市场全部。我相信两者相加是大于二的,因为能知道越多信息,越多的角度去观察市场,才能做出更好的决策。






发明者量化交易之所以运营这个公众号,旨在改变当前量化圈无干货,交流闭塞,骗子横行的现状,打造一个更纯净的量化圈子。   更多内容请访问我们的网站(www.fmz.com)


您的转发,将是支持我们继续创作更多干货的动力!如果您觉得这篇文章对您有帮助,请多多转发,支持我们。分享也是一种智慧!




长按二维码识别关注我们

联系我们微信:fmz_zhangchao邮箱:hi@fmz.com网址:www.fmz.com





分享到 :
0 人收藏
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

积分:20
帖子:4
精华:0
期权论坛 期权论坛
发布
内容

下载期权论坛手机APP