using System; using System.Collections.Generic; using System.Linq; namespace Decentralized.Domain { /// 一天一根蜡烛:开盘接前一天的收盘价、包括夜间变动和白天真实发生过的最高 / 最低、夜间结算前的收盘价;成交额分玩家和 NPC 大户(信用点)。 public sealed class Candle { public int Day; public double O, H, L, C, VolPlayer, VolNpc; public bool Closed; } /// /// 日 K 历史(按币种)。开门时开一根,白天的价格变动(开门波动、插针、大户、玩家大单)更新高低和现价,夜间结算时收盘。 /// 没有发生过的日内走势不编造:没有事件的日子高低就等于开收。 /// public sealed class CandleBook { public const int Keep = 60; public Dictionary> Series = new Dictionary>(); public List Of(string asset) => Series.TryGetValue(asset, out var s) ? s : new List(); /// 今天的蜡烛:没有就按现价开一根(读档时补上,开盘价就是读档时的价格)。 public Candle Today(string asset, int day, double price) { if (!Series.TryGetValue(asset, out var s)) Series[asset] = s = new List(); var c = s.Count > 0 ? s[s.Count - 1] : null; if (c != null && c.Day == day) return c; c = new Candle { Day = day, O = price, H = price, L = price, C = price }; s.Add(c); while (s.Count > Keep) s.RemoveAt(0); return c; } /// /// 开门:新开一根。币是全天候交易的,所以开盘价接昨天的收盘价,夜里的回归和开门波动都算进这根蜡烛(没有跳空); /// 没有昨天的(刚开始记录)就从现价开。 /// public void Open(string asset, int day, double price) { var s = Of(asset); var prev = s.Count > 0 && s[s.Count - 1].Day < day ? s[s.Count - 1] : null; var c = Today(asset, day, price); if (c.Closed) return; double o = prev != null ? prev.C : price; c.O = o; c.H = Math.Max(o, price); c.L = Math.Min(o, price); c.C = price; } /// 白天的价格变动。 public void Tick(string asset, int day, double price, double volume = 0, bool player = false) { var c = Today(asset, day, price); if (c.Closed) return; c.H = Math.Max(c.H, price); c.L = Math.Min(c.L, price); c.C = price; if (player) c.VolPlayer += Math.Abs(volume); else c.VolNpc += Math.Abs(volume); } /// 夜间结算:收盘。 public void Close(string asset, int day, double price) { Tick(asset, day, price); Today(asset, day, price).Closed = true; } /// NPC 当天的成交额(信用点):基础量随池深,波动越大成交越多。 public static double NpcVolume(double depth, double share, double absMove, Rng rng) => depth * share * (1 + Tuning.ChartVolMove * absMove) * rng.Range(0.6, 1.4); /// 收盘价的 n 日均线(不足 n 根时用已有的);每根蜡烛一个值。 public static List Ma(IList s, int n) { var r = new List(); for (int i = 0; i < s.Count; i++) { int a = Math.Max(0, i - n + 1); double sum = 0; for (int j = a; j <= i; j++) sum += s[j].C; r.Add(sum / (i - a + 1)); } return r; } } }