XFE Git
XFE Studio Git
Git 首页 全局搜索
XFE 主站 文档 NuGet

XFEEDToolBox

【WinUI】XFE精英危险工具箱

公开
关注 0 Fork 0 Star 0
返回提交历史

XFEstudio/XFEEDToolBox

fix: apply confirmed purchases to both native and public stock observations

e222656
XFE工作室室长 <mail@xfegzs.com>
提交于

代码差异

6 个文件 +30 -9
Modified XFEEDToolBox.Core/Execution/AutomaticSupplyPlanner.cs +8 -1
@@ -5,7 +5,8 @@ using XFEEDToolBox.Core.Planning;
5 5 namespace XFEEDToolBox.Core.Execution;
6 6
7 7 public sealed record AutomaticSupplyRequest(AutomaticTradeConfiguration Configuration,PlayerState Player,decimal Credits,decimal Reserve,
8 IReadOnlyDictionary<long,IReadOnlyList<CommodityQuote>> ObservedQuotes);
8 IReadOnlyDictionary<long,IReadOnlyList<CommodityQuote>> ObservedQuotes)
9 {public IReadOnlyList<ConfirmedTradeReceipt> ConfirmedTrades{get;init;}=[];}
9 10
10 11 public sealed record AutomaticSupplyChoice(Station Source,TradeLeg Delivery,long Supply,long Demand,int FreeCapacity,
11 12 double EmptyReturnMinutes,double RepositionMinutes,decimal EstimatedNetProfit,double EstimatedMinutes)
@@ -22,6 +23,12 @@ public sealed record AutomaticSupplyChoice(Station Source,TradeLeg Delivery,long
22 23 /// <summary>Ranks every compatible CG supply station by a real bounded load and complete repeated-trip time.</summary>
23 24 public static class AutomaticSupplyPlanner
24 25 {
26 public static MarketBook DeductConfirmedTrades(MarketBook book,IEnumerable<ConfirmedTradeReceipt> receipts)
27 {
28 var rows=book.Quotes.GroupBy(q=>q.MarketId).ToDictionary(g=>g.Key,g=>(IReadOnlyList<CommodityQuote>)g.ToArray());
29 return book with{Quotes=DeductConfirmedTrades(rows,receipts).Values.SelectMany(q=>q).ToArray()};
30 }
31
25 32 public static MarketBook MergeObservations(MarketBook cache,IReadOnlyDictionary<long,IReadOnlyList<CommodityQuote>> observations)
26 33 {
27 34 var latest=observations.Where(p=>p.Value.Count>0).ToDictionary(p=>p.Key,p=>p.Value.Max(q=>q.CollectedAt));
Modified XFEEDToolBox.Core/Execution/AutomaticTradeEngine.cs +5 -3
@@ -120,7 +120,7 @@ public sealed class AutomaticTradeEngine(AutomaticTradeConfiguration configurati
120 120 return rows;
121 121 }
122 122 private bool FreshQuotes(Station station)=>quotes.TryGetValue(station.MarketId,out var rows)&&rows.Count>0&&rows.All(q=>DateTimeOffset.UtcNow-q.CollectedAt<TimeSpan.FromMinutes(30));
123 private IReadOnlyDictionary<long,IReadOnlyList<CommodityQuote>> RemainingObservedQuotes()
123 private IReadOnlyList<ConfirmedTradeReceipt> ConfirmedSupplyTrades()
124 124 {
125 125 var receipts=new List<ConfirmedTradeReceipt>();
126 126 foreach(var file in Directory.EnumerateDirectories(root,"journey-*").Select(p=>Path.Combine(p,"journey.json")).Where(File.Exists))
@@ -129,7 +129,7 @@ public sealed class AutomaticTradeEngine(AutomaticTradeConfiguration configurati
129 129 if(checkpoint.Commander!=initial.CommanderId||checkpoint.ShipId!=initial.CurrentShipId)continue;
130 130 if(checkpoint.Bought is{} bought)receipts.Add(bought);if(checkpoint.Sold is{} sold)receipts.Add(sold);
131 131 }
132 return AutomaticSupplyPlanner.DeductConfirmedTrades(quotes,receipts);
132 return receipts;
133 133 }
134 134 private async Task<bool> SelectSourceAsync(CancellationToken token)
135 135 {
@@ -138,8 +138,10 @@ public sealed class AutomaticTradeEngine(AutomaticTradeConfiguration configurati
138 138 await StateAsync("selecting-source","正在按供应量、实际货舱和完整循环时间重新比较全部 CG 货源",token:token);
139 139 var wallet=await driver.RefreshWalletAsync(token);var current=player();
140 140 var services=current.MarketId is >0?await driver.ReadServiceBudgetAsync(current.MarketId.Value,token):0;
141 var receipts=ConfirmedSupplyTrades();
141 142 var choice=await selectSource(new(configuration with{Source=source},current,wallet.Credits,
142 configuration.PurchaseReserve(wallet.Credits,current.Rebuy,services),RemainingObservedQuotes()),token).ConfigureAwait(false);
143 configuration.PurchaseReserve(wallet.Credits,current.Rebuy,services),AutomaticSupplyPlanner.DeductConfirmedTrades(quotes,receipts))
144 {ConfirmedTrades=receipts},token).ConfigureAwait(false);
143 145 if(choice is null)
144 146 {
145 147 await StateAsync("waiting-market","当前合格货源的供应、需求或资金不足,保持停靠等待新报价;未沿用已耗尽的货源。",token:token);
Modified XFEEDToolBox.Test/AutomaticSupplyPlannerTests.cs +11 -0
@@ -71,6 +71,17 @@ namespace XFEEDToolBox.Test;
71 71 var refreshed=AutomaticSupplyPlanner.MergeObservations(cached with{Quotes=[Quote(999),Quote(1,2000) with{CollectedAt=Now.AddMinutes(1)}]},observed);
72 72 Check.Equal(1200,AutomaticSupplyPlanner.Calculate(refreshed,Request,Destination,["uranium"])[0].Order.Quantity);
73 73 }
74 [Test]public void PublicQuoteBetweenTheDockedObservationAndOurConfirmedPurchaseCannotResurrectConsumedStock()
75 {
76 var buy=new ConfirmedTradeReceipt("buy",1,"uranium",875,100,1000000,912500,0,875,"commander",8,Now.AddHours(-1),Now.AddSeconds(30),true,true);
77 IReadOnlyDictionary<long,IReadOnlyList<CommodityQuote>> observed=new Dictionary<long,IReadOnlyList<CommodityQuote>>{[1]=[Quote(1,0)]};
78 var cache=new MarketBook([Destination,Station(1)],[Quote(999),Quote(1,875) with{CollectedAt=Now.AddSeconds(10)}]);
79 var adjusted=AutomaticSupplyPlanner.DeductConfirmedTrades(cache,[buy]);
80 Check.Equal(0,AutomaticSupplyPlanner.Calculate(AutomaticSupplyPlanner.MergeObservations(adjusted,observed),Request,Destination,["uranium"]).Count);
81 var replenished=cache with{Quotes=[Quote(999),Quote(1,5000) with{CollectedAt=Now.AddMinutes(1)}]};
82 var newer=AutomaticSupplyPlanner.DeductConfirmedTrades(replenished,[buy]);
83 Check.Equal(1200,AutomaticSupplyPlanner.Calculate(AutomaticSupplyPlanner.MergeObservations(newer,observed),Request,Destination,["uranium"])[0].Order.Quantity);
84 }
74 85 [Test]public void ActualLargeShipPadAndUserSourceTypesApplyToEverySupplier()
75 86 {
76 87 var small=Station(1) with{MaxLandingPad=LandingPad.Medium};var carrier=Station(2) with{Type="FleetCarrier",IsFleetCarrier=true};
Modified XFEEDToolBox/ViewModels/AutomaticSupplyViewModel.cs +2 -1
@@ -44,7 +44,8 @@ public partial class ToolboxViewModel
44 44 var stations=cached.Stations.Append(config.Source).Append(config.Destination).DistinctBy(s=>s.MarketId).ToArray();
45 45 // A live station snapshot replaces its cached rows completely,
46 46 // including zero stock and commodities no longer offered.
47 var merged=AutomaticSupplyPlanner.MergeObservations(cached with{Stations=stations},value.ObservedQuotes);
47 var remaining=AutomaticSupplyPlanner.DeductConfirmedTrades(cached,value.ConfirmedTrades);
48 var merged=AutomaticSupplyPlanner.MergeObservations(remaining with{Stations=stations},value.ObservedQuotes);
48 49 var choices=AutomaticSupplyPlanner.Calculate(merged,request,config.Destination,accepted,token:token,progress:progress);
49 50 var proof=new{at=request.AsOf,goalId=goal.Id,request,stations=cached.Stations.Count,quotes=merged.Quotes.Count,
50 51 supplyBasis="缓存供需估算;实际到站报价优先,采购前及每轮交付后重算",choices};
Modified docs/INTERFACE-0.4.24.md +2 -2
@@ -1,6 +1,6 @@
1 1 # 0.4.24:按实际供货量比较 CG 循环收益
2 2
3 CG 自动跑商现在会在交付完成后、到达货源读取真实行情后重新比较货源。搜索沿用规划界面的中心、半径、来源类型、最大航段、行情时效和风险约束;每个采购站和交付站都核对真实船型需要的停机坪。所有合格站点并行参与计算,最多同时使用 8 个工作线程;展示前 8 个方案不限制参与计算的站点数量。进度条按实际已处理站点更新。
3 CG 自动跑商现在会在交付完成后、到达货源读取真实行情后重新比较货源。搜索沿用规划界面的中心、半径、来源类型、最大航段、行情时效和风险约束;每个采购站和交付站都核对真实船型需要的停机坪。所有合格站点并行参与计算,最多同时使用 8 个工作线程;返回前 8 个候选供自动选择并记录,不限制参与计算的站点数量。进度条按实际已处理站点更新。
4 4
5 5 每个候选订单数量取以下最小值:实际空舱、该商品库存、交付站需求,以及扣除重购费、运营储备和固定投资限制后的可购买数量。不再对规划货舱施加 2048 吨上限。正式自动交易仍使用原生通道支持的单商品批次,不将无法执行的混载收益记入自动跑商估算。
6 6
@@ -8,7 +8,7 @@ CG 自动跑商现在会在交付完成后、到达货源读取真实行情后
8 8
9 9 完整循环包括载货交付、空载返程,以及从第三地点更换货源的必要转场;航程按当前飞船的保守满载跳距、进站距离、跃迁及停靠时间计算。结果为估算,不倍乘已经反映在 CG 报价中的奖励。风险结合安保、供需比例和报价时效评估。
10 10
11 真实到站行情会整体替换该站旧缓存;在旧报价之后发生的本船已确认采购和销售分别扣减可用库存与需求,按原订单键去重,不假定后续补货。更新的真实报价取代旧扣减,因此不会重复扣库存。没有符合条件的货源时保持停靠,等待新的行情。
11 真实到站行情会整体替换该站旧缓存;原生观测和公共报价都根据各自的采集时间,扣除之后发生的本船已确认采购和销售,按原订单键去重,不假定后续补货。发生在成交之后的更新报价不再扣除这笔旧成交,因此不会重复扣库存。没有符合条件的货源时保持停靠,等待新的行情。
12 12
13 13 启动时先恢复未完成的原订单和回执,已有货物交付之前不会改货源或重新采购。确认回程的路线先回到该批次的实际货源;CG 空载返程模式在交付后立即重新选源。轮次以指挥官、飞船、目标活动和实际销售回执累计,更换来源不清零。
14 14
Modified docs/VALIDATION-0.4.24.md +2 -2
@@ -1,8 +1,8 @@
1 1 # 0.4.24 验证记录
2 2
3 - 全部托管测试:1492 项,1486 通过,0 失败,6 跳过;用时 99.865 秒。新增 10 项测试覆盖实际 875/1200 吨收益比较、4096 吨货舱、资金/需求/空舱约束、空载返程及转场、库存耗尽、最新报价及真实补货替换、已确认采购去重扣减、停机坪/来源类型、501 个货源的全量计算与进度,以及跨货源/重启后的轮次累计。
3 - 全部托管测试:1493 项,1487 通过,0 失败,6 跳过;用时 83.731 秒。新增 11 项测试覆盖实际 875/1200 吨收益比较、4096 吨货舱、资金/需求/空舱约束、空载返程及转场、库存耗尽、最新报价及真实补货替换、已确认采购去重扣减、公共报价先更新而本船采购后确认的时序、停机坪/来源类型、501 个货源的全量计算与进度,以及跨货源/重启后的轮次累计。
4 4 - 实机发现自动降落接管失败后,旧输入会话的停止标记会阻止后续菜单恢复。恢复现在先释放旧输入,再通过现有保护授权器重新核验连续健康数据;真实受损和紧急保护仍生效。该修改后重跑自动化相关 33 项测试:32 通过、0 失败、1 跳过,包含实际引擎的释放、重新授权与菜单恢复顺序验证。
5 - Windows x64 自包含发布成功:`dist/XFEEDToolBox-0.4.24-win-x64`。完整测试报告与构建输出保存在本地忽略目录 `work/tests/toolbox-0.4.24-reviewed-final`、`work/tests/automatic-0.4.24-release-final`、`work/release-0.4.24/publish-final.log`。部署的程序、Core、内嵌支持与图标 SHA256 均与最终发布一致。
5 - Windows x64 自包含发布成功:`dist/XFEEDToolBox-0.4.24-win-x64`。完整测试报告与构建输出保存在本地忽略目录 `work/tests/toolbox-0.4.24-stock-order-final`、`work/tests/automatic-0.4.24-release-final`、`work/release-0.4.24/publish-stock-order-final.log`。部署后核对程序、Core、内嵌支持与图标 SHA256。
6 6 - 对真实周边缓存执行只读比较:65 个站点、17163 条报价,读取及计算合计约 301 毫秒。未截断参与站点,也未扫描或校验完整行情数据库。数据与可复算参数保存在 `work/supply-review/actual-comparison.json`;此项没有向游戏提交订单。
7 7 - 真实运行使用原 CG 工作目录与采购回执恢复,原 875 吨铀已在 AD Leonis / Homer Platform 售出,CG 贡献由 14610 增至 15485;确认完成 1 轮,未重复采购。后续按完整循环收益选择可装 1200 吨的货源。真实后续进度及行情选择以原工作目录的 `state.json`、`supply-candidates-latest.json`、旅程回执与 CG 贡献确认文件为准。
8 8 - 按 background-visual-check 技能,以最终部署的真实窗口后台取图,原图、表单/执行概览局部、原比例分块与 OCR 交叉核验;启动前两项验收通过,记录位于 `work/visual/supply-0.4.24/idle-final-build/verdict.json`。运行中的货源摘要另行核验,不以启动成功替代视觉结论。