Files
my_wiki/raw/期货/01-基本分析逻辑/焦煤日报/scripts/Generate-JmDailyReport.ps1
T

183 lines
7.7 KiB
PowerShell
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
param(
[switch]$Force,
[switch]$DryRun
)
$ErrorActionPreference = 'Stop'
$Workspace = 'C:\Users\12637\Desktop\hermes\焦煤'
$ReportDir = Join-Path $Workspace '日报'
$LogDir = Join-Path $Workspace '日志'
$Today = Get-Date -Format 'yyyy-MM-dd'
$RunAt = Get-Date -Format 'yyyy-MM-dd HH:mm:ss'
$ReportPath = Join-Path $ReportDir "$Today`_焦煤日报.md"
$LogPath = Join-Path $LogDir 'auto_daily_report.log'
New-Item -ItemType Directory -Force -Path $ReportDir, $LogDir | Out-Null
function Write-AutoLog {
param([string]$Message)
$line = "$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss') $Message"
Add-Content -LiteralPath $LogPath -Value $line -Encoding UTF8
}
function To-DecimalOrNull {
param([string]$Value)
if ([string]::IsNullOrWhiteSpace($Value)) { return $null }
$style = [Globalization.NumberStyles]::Float
$culture = [Globalization.CultureInfo]::InvariantCulture
return [decimal]::Parse($Value, $style, $culture)
}
function Format-Price {
param([object]$Value)
if ($null -eq $Value -or [string]::IsNullOrWhiteSpace([string]$Value)) { return '待核验' }
$number = [decimal]$Value
return $number.ToString('0.0', [Globalization.CultureInfo]::InvariantCulture)
}
function Format-Int {
param([object]$Value)
if ($null -eq $Value -or [string]::IsNullOrWhiteSpace([string]$Value)) { return '待核验' }
$number = [decimal]$Value
return ([int]$number).ToString('N0', [Globalization.CultureInfo]::GetCultureInfo('zh-CN'))
}
try {
$url = 'https://hq.sinajs.cn/list=nf_JM2609,nf_JM0'
$headers = @{
Referer = 'https://finance.sina.com.cn/futures/quotes/JM0.shtml'
'User-Agent' = 'Mozilla/5.0'
}
$response = Invoke-WebRequest -Uri $url -Headers $headers -TimeoutSec 30
$content = $response.Content
$match = [regex]::Match($content, 'hq_str_nf_JM2609="(?<body>[^"]+)"')
if (-not $match.Success) {
$match = [regex]::Match($content, 'hq_str_nf_JM0="(?<body>[^"]+)"')
}
if (-not $match.Success) {
throw '未能从新浪行情接口解析 JM2609/JM0 行情串。'
}
$fields = $match.Groups['body'].Value -split ','
if ($fields.Count -lt 18) {
throw "行情字段数量不足:$($fields.Count)。"
}
$quoteDate = $fields[17]
if (($quoteDate -ne $Today) -and (-not $Force)) {
Write-AutoLog "跳过:行情日期 $quoteDate 与本机日期 $Today 不一致,可能为非交易日或数据未更新。"
exit 0
}
$contractName = $fields[0]
$quoteTimeRaw = $fields[1]
$quoteTime = if ($quoteTimeRaw.Length -eq 6) { "$($quoteTimeRaw.Substring(0,2)):$($quoteTimeRaw.Substring(2,2)):$($quoteTimeRaw.Substring(4,2))" } else { $quoteTimeRaw }
$open = To-DecimalOrNull $fields[2]
$high = To-DecimalOrNull $fields[3]
$low = To-DecimalOrNull $fields[4]
$last = To-DecimalOrNull $fields[8]
if ($null -eq $last -or $last -eq 0) { $last = To-DecimalOrNull $fields[5] }
$settle = To-DecimalOrNull $fields[9]
$prevSettle = To-DecimalOrNull $fields[10]
$openInterest = To-DecimalOrNull $fields[13]
$volume = To-DecimalOrNull $fields[14]
$change = $null
$pct = $null
if ($null -ne $last -and $null -ne $prevSettle -and $prevSettle -ne 0) {
$change = $last - $prevSettle
$pct = [math]::Round((([double]$change / [double]$prevSettle) * 100), 2)
}
$direction = '持平'
if ($null -ne $change) {
if ($change -gt 0) { $direction = '上涨' }
elseif ($change -lt 0) { $direction = '下跌' }
}
$closeLocation = '待核验'
if ($null -ne $last -and $null -ne $high -and $null -ne $low -and $high -gt $low) {
$pos = ([double]($last - $low) / [double]($high - $low))
if ($pos -ge 0.67) { $closeLocation = '收在日内偏高区间' }
elseif ($pos -le 0.33) { $closeLocation = '收在日内偏低区间' }
else { $closeLocation = '收在日内中部区间' }
}
$changeText = if ($null -ne $change) { $change.ToString('+0.0;-0.0;0.0', [Globalization.CultureInfo]::InvariantCulture) } else { '待核验' }
$pctText = if ($null -ne $pct) { $pct.ToString('+0.00;-0.00;0.00', [Globalization.CultureInfo]::InvariantCulture) + '%' } else { '待核验' }
$report = @"
# $Today 焦煤期货日报(自动生成)
> 自动生成时间:$RunAt
> 数据边界:盘面来自新浪期货行情接口;现货、基差、供需、重点新闻需用 finance-mcp / 妙想 MCP 或人工源二次补充。自动版不编写未核验数字。
## 主要结论
- 主力合约:$contractName,收报 $(Format-Price $last) 元/吨,较昨结 $changeText$pctText),日内区间 $(Format-Price $low)-$(Format-Price $high) 元/吨,$closeLocation
- 量仓结构:成交量 $(Format-Int $volume) 手,持仓量 $(Format-Int $openInterest) 手。字段口径按新浪行情串解析为“持仓量在成交量前”,如交易所或第三方口径冲突,以交易所/可靠第三方二次核验为准。
- 盘面判断:当日盘面$direction,短线仍需观察价格能否站稳日内高位;若回落至昨结或日内低位附近,则说明上涨动能减弱。
## 关键数据
| 指标 | 数值 | 备注 |
|---|---:|---|
| 主力合约 | $contractName | 新浪行情 |
| 最新/收盘价 | $(Format-Price $last) 元/吨 | 行情时间 $quoteTime |
| 开盘价 | $(Format-Price $open) 元/吨 | 自动抓取 |
| 最高价 | $(Format-Price $high) 元/吨 | 自动抓取 |
| 最低价 | $(Format-Price $low) 元/吨 | 自动抓取 |
| 昨结 | $(Format-Price $prevSettle) 元/吨 | 自动抓取 |
| 结算价 | $(Format-Price $settle) 元/吨 | 自动抓取 |
| 涨跌 | $changeText | 相对昨结 |
| 涨跌幅 | $pctText | 相对昨结 |
| 成交量 | $(Format-Int $volume) 手 | 新浪字段 14 |
| 持仓量 | $(Format-Int $openInterest) 手 | 新浪字段 13 |
日内区间:$(Format-Price $low) ├──────── $(Format-Price $last) ────────┤ $(Format-Price $high)
## 重点新闻
- 【待补充】近三日煤矿安监、复产、停产、事故、政策扰动。
- 【待补充】蒙煤通关、口岸库存、进口煤报价变化。
- 【待补充】焦化利润、钢厂铁水、成材成交及负反馈风险。
## 现货、基差与供需
| 模块 | 状态 | 结论 |
|---|---|---|
| 现货价格 | 待 MCP / 人工核验 | 不自动填数 |
| 基差 | 待 MCP / 人工核验 | 不自动填数 |
| 供给 | 待 MCP / 人工核验 | 关注山西安监、煤矿复产、蒙煤通关 |
| 需求 | 待 MCP / 人工核验 | 关注铁水、焦炭利润、钢厂补库 |
| 库存 | 待 MCP / 人工核验 | 关注港口、煤矿、焦钢企业库存 |
## 下个交易日预测
- 基准情形:若价格维持在 $(Format-Price $last) 元/吨附近并放量不破日内低点,短线偏强震荡。
- 上行情形:若突破并站稳 $(Format-Price $high) 元/吨上方,说明多头延续,关注整数关口及前高压力。
- 回落情形:若跌回昨结 $(Format-Price $prevSettle) 元/吨附近,说明当日上涨被消化,关注资金离场和现货跟涨不足风险。
## 数据与来源
- 盘面:新浪期货行情 nf_JM2609,nf_JM0,行情日期 $quoteDate,行情时间 $quoteTime
- 自动任务:Windows 任务计划程序工作日 15:30 触发。
- 质量控制:现货、新闻、供需未核验时必须保留“待补充/待核验”,不得编写具体数值。
"@
if ($DryRun) {
Write-Output $report
Write-AutoLog "DryRun:已生成预览,未写入 $ReportPath。"
}
else {
Set-Content -LiteralPath $ReportPath -Value $report -Encoding UTF8
Write-AutoLog "完成:已写入 $ReportPath。"
}
}
catch {
Write-AutoLog "失败:$($_.Exception.Message)"
throw
}