пятница, 10 октября 2025 г.

25.10.09, Stat, Test, Norm, DeepSeek,

25.10.09, Stat, Test, Norm, Model, Volatility, DeepSeek,

Отлично понимаю вашу проблему! Вы описываете нестационарный процесс с локальной автокорреляцией, а обычное нормальное распределение дает стационарный белый шум. Давайте создадим генератор, который имитирует реальные котировки.

1. Модель с дрейфом и локальной волатильностью

csharp
public class RealisticStockPriceGenerator
{
    private readonly NormalDistributionGenerator _normalGenerator;
    private readonly Random _random;
    private double _currentPrice;
    private double _currentDrift;
    private double _currentVolatility;
    private readonly double _meanReversionSpeed;
    private readonly double _volatilityMeanReversion;
    
    public RealisticStockPriceGenerator(double initialPrice, int? seed = null)
    {
        _normalGenerator = new NormalDistributionGenerator(seed: seed);
        _random = seed.HasValue ? new Random(seed.Value) : new Random();
        _currentPrice = initialPrice;
        _currentDrift = 0;
        _currentVolatility = 0.02; // 2% волатильность
        _meanReversionSpeed = 0.05; // Скорость возврата к среднему
        _volatilityMeanReversion = 0.1; // Скорость изменения волатильности
    }
    
    public double NextPrice()
    {
        // 1. Обновляем дрейф (медленно меняется)
        _currentDrift = _currentDrift * 0.95 + _normalGenerator.Next() * 0.0005;
        
        // 2. Обновляем волатильность (кластеризация волатильности)
        _currentVolatility = Math.Max(0.001, 
            _currentVolatility * 0.9 + Math.Abs(_normalGenerator.Next()) * 0.01);
        
        // 3. Генерируем возврат с учетом текущего дрейфа и волатильности
        double returns = _currentDrift + _currentVolatility * _normalGenerator.Next();
        
        // 4. Применяем к цене (геометрическое броуновское движение)
        _currentPrice *= Math.Exp(returns);
        
        return _currentPrice;
    }
    
    public double[] GeneratePriceSeries(int count)
    {
        var prices = new double[count];
        for (int i = 0; i < count; i++)
        {
            prices[i] = NextPrice();
        }
        return prices;
    }
}

2. Модель с каналами и поддержкой/сопротивлением

csharp
public class ChannelBasedPriceGenerator
{
    private readonly NormalDistributionGenerator _normalGenerator;
    private double _currentPrice;
    private double _channelCenter;
    private double _channelWidth;
    private double _trend;
    private int _timeInChannel;
    
    public ChannelBasedPriceGenerator(double initialPrice, int? seed = null)
    {
        _normalGenerator = new NormalDistributionGenerator(seed: seed);
        _currentPrice = initialPrice;
        _channelCenter = initialPrice;
        _channelWidth = initialPrice * 0.05; // 5% ширина канала
        _trend = 0;
        _timeInChannel = 0;
    }
    
    public double NextPrice()
    {
        _timeInChannel++;
        
        // Раз в 100-200 шагов меняем канал
        if (_timeInChannel > 100 + _normalGenerator.Next() * 100)
        {
            CreateNewChannel();
        }
        
        // Локальные колебания внутри канала
        double localMove = _normalGenerator.Next() * _channelWidth * 0.1;
        
        // Притяжение к центру канала (сила поддержки/сопротивления)
        double distanceToCenter = _channelCenter - _currentPrice;
        double meanReversionForce = distanceToCenter * 0.1;
        
        // Трендовая составляющая
        double trendMove = _trend;
        
        double newPrice = _currentPrice + localMove + meanReversionForce + trendMove;
        
        // Отскок от границ канала
        if (Math.Abs(newPrice - _channelCenter) > _channelWidth)
        {
            localMove *= -0.5; // Отскок
            newPrice = _currentPrice + localMove + meanReversionForce + trendMove;
        }
        
        _currentPrice = newPrice;
        return _currentPrice;
    }
    
    private void CreateNewChannel()
    {
        // Новый центр канала - случайное смещение ±10%
        double shift = (_normalGenerator.Next() * 0.2 - 0.1) * _channelCenter;
        _channelCenter += shift;
        
        // Новая ширина канала 3-8%
        _channelWidth = _channelCenter * (0.03 + _normalGenerator.Next() * 0.05);
        
        // Новый тренд (очень медленный)
        _trend = _normalGenerator.Next() * _channelCenter * 0.0001;
        
        _timeInChannel = 0;
    }
    
    public (double[] prices, double[] centers, double[] widths) GenerateSeriesWithChannels(int count)
    {
        var prices = new double[count];
        var centers = new double[count];
        var widths = new double[count];
        
        for (int i = 0; i < count; i++)
        {
            prices[i] = NextPrice();
            centers[i] = _channelCenter;
            widths[i] = _channelWidth;
        }
        
        return (prices, centers, widths);
    }
}

3. Продвинутая модель с памятью и кластеризацией

csharp
public class AdvancedPriceGenerator
{
    private readonly NormalDistributionGenerator _normalGenerator;
    private readonly List<double> _priceHistory;
    private readonly int _memorySize;
    private double _currentPrice;
    private double _localMean;
    private double _localVolatility;
    
    public AdvancedPriceGenerator(double initialPrice, int memorySize = 50, int? seed = null)
    {
        _normalGenerator = new NormalDistributionGenerator(seed: seed);
        _priceHistory = new List<double> { initialPrice };
        _memorySize = memorySize;
        _currentPrice = initialPrice;
        _localMean = initialPrice;
        _localVolatility = initialPrice * 0.02;
    }
    
    public double NextPrice()
    {
        // Обновляем локальную статистику
        UpdateLocalStatistics();
        
        // Генерируем возврат, зависящий от предыдущих значений
        double returns = GenerateCorrelatedReturns();
        
        // Применяем к цене
        _currentPrice *= Math.Exp(returns);
        _priceHistory.Add(_currentPrice);
        
        // Поддерживаем размер истории
        if (_priceHistory.Count > _memorySize)
            _priceHistory.RemoveAt(0);
            
        return _currentPrice;
    }
    
    private void UpdateLocalStatistics()
    {
        if (_priceHistory.Count < 10) return;
        
        // Локальное среднее (скользящее среднее)
        _localMean = _priceHistory.Average();
        
        // Локальная волатильность (на основе недавних данных)
        var recentPrices = _priceHistory.TakeLast(20).ToArray();
        double mean = recentPrices.Average();
        double variance = recentPrices.Average(p => Math.Pow(p - mean, 2));
        _localVolatility = Math.Sqrt(variance) / mean;
        
        // Ограничиваем волатильность
        _localVolatility = Math.Max(0.005, Math.Min(0.15, _localVolatility));
    }
    
    private double GenerateCorrelatedReturns()
    {
        // Автокорреляция - текущее значение зависит от предыдущих
        double correlatedNoise = 0;
        double totalWeight = 0;
        
        for (int i = 1; i <= Math.Min(5, _priceHistory.Count - 1); i++)
        {
            double weight = Math.Exp(-i * 0.5); // Экспоненциально убывающие веса
            double pastReturn = Math.Log(_priceHistory[^i] / _priceHistory[^(i + 1)]);
            correlatedNoise += pastReturn * weight;
            totalWeight += weight;
        }
        
        correlatedNoise /= totalWeight;
        
        // Случайная компонента + память
        double randomComponent = _normalGenerator.Next() * _localVolatility;
        double memoryComponent = correlatedNoise * 0.3;
        
        // Очень медленный дрейф к локальному среднему
        double meanReversion = (_localMean - _currentPrice) / _currentPrice * 0.01;
        
        return memoryComponent + randomComponent + meanReversion;
    }
    
    public (double[] prices, double[] localMean, double[] localVolatility) GenerateSeriesWithStats(int count)
    {
        var prices = new double[count];
        var means = new double[count];
        var volatilities = new double[count];
        
        for (int i = 0; i < count; i++)
        {
            prices[i] = NextPrice();
            means[i] = _localMean;
            volatilities[i] = _localVolatility;
        }
        
        return (prices, means, volatilities);
    }
}

4. Генератор с режимами рынка

csharp
public class RegimeSwitchingPriceGenerator
{
    public enum MarketRegime
    {
        Trending,       // Трендовый режим
        MeanReverting,  // Флэтовый режим  
        Volatile,       // Волатильный режим
        Calm            // Спокойный режим
    }
    
    private readonly NormalDistributionGenerator _normalGenerator;
    private double _currentPrice;
    private MarketRegime _currentRegime;
    private int _regimeDuration;
    private int _timeInRegime;
    
    public RegimeSwitchingPriceGenerator(double initialPrice, int? seed = null)
    {
        _normalGenerator = new NormalDistributionGenerator(seed: seed);
        _currentPrice = initialPrice;
        _currentRegime = MarketRegime.Calm;
        _regimeDuration = 200 + (int)(_normalGenerator.Next() * 300);
        _timeInRegime = 0;
    }
    
    public (double price, MarketRegime regime) NextPrice()
    {
        _timeInRegime++;
        
        // Смена режима
        if (_timeInRegime > _regimeDuration)
        {
            SwitchRegime();
        }
        
        double returns = GenerateReturnsByRegime();
        _currentPrice *= Math.Exp(returns);
        
        return (_currentPrice, _currentRegime);
    }
    
    private void SwitchRegime()
    {
        var regimes = Enum.GetValues<MarketRegime>();
        _currentRegime = regimes[_normalGenerator.Next() > 0 ? 2 : 0]; // Упрощенная логика
        _regimeDuration = 100 + (int)(Math.Abs(_normalGenerator.Next()) * 400);
        _timeInRegime = 0;
    }
    
    private double GenerateReturnsByRegime()
    {
        return _currentRegime switch
        {
            MarketRegime.Trending => _normalGenerator.Next() * 0.01 + 0.001, // Вверх + шум
            MarketRegime.MeanReverting => _normalGenerator.Next() * 0.005,   // Маленькие колебания
            MarketRegime.Volatile => _normalGenerator.Next() * 0.03,         // Большие колебания
            MarketRegime.Calm => _normalGenerator.Next() * 0.002,           // Очень маленькие
            _ => _normalGenerator.Next() * 0.01
        };
    }
    
    public (double[] prices, MarketRegime[] regimes) GenerateSeriesWithRegimes(int count)
    {
        var prices = new double[count];
        var regimes = new MarketRegime[count];
        
        for (int i = 0; i < count; i++)
        {
            (prices[i], regimes[i]) = NextPrice();
        }
        
        return (prices, regimes);
    }
}

5. Пример использования и визуализация

csharp
class Program
{
    static void Main()
    {
        // Тестируем разные генераторы
        Console.WriteLine("ГЕНЕРАЦИЯ РЕАЛИСТИЧНЫХ БИРЖЕВЫХ ДАННЫХ");
        Console.WriteLine("=====================================\n");
        
        // 1. Базовая модель
        var basicGenerator = new RealisticStockPriceGenerator(100, seed: 42);
        var basicPrices = basicGenerator.GeneratePriceSeries(500);
        
        // 2. Модель с каналами
        var channelGenerator = new ChannelBasedPriceGenerator(100, seed: 42);
        var (channelPrices, centers, widths) = channelGenerator.GenerateSeriesWithChannels(500);
        
        // 3. Продвинутая модель
        var advancedGenerator = new AdvancedPriceGenerator(100, seed: 42);
        var (advancedPrices, localMeans, localVolatilities) = advancedGenerator.GenerateSeriesWithStats(500);
        
        // 4. Модель с режимами
        var regimeGenerator = new RegimeSwitchingPriceGenerator(100, seed: 42);
        var (regimePrices, regimes) = regimeGenerator.GenerateSeriesWithRegimes(500);
        
        // Анализ результатов
        AnalyzeSeries("Базовая модель", basicPrices);
        AnalyzeSeries("Модель с каналами", channelPrices);
        AnalyzeSeries("Продвинутая модель", advancedPrices);
        AnalyzeSeries("Модель с режимами", regimePrices);
        
        // Визуализация (псевдографика)
        VisualizePrices(advancedPrices, "Продвинутая модель");
    }
    
    static void AnalyzeSeries(string name, double[] prices)
    {
        double returnsVolatility = CalculateReturnsVolatility(prices);
        double autocorrelation = CalculateAutocorrelation(prices, lag: 1);
        double hurstExponent = EstimateHurstExponent(prices);
        
        Console.WriteLine($"{name}:");
        Console.WriteLine($"  Волатильность: {returnsVolatility:P3}");
        Console.WriteLine($"  Автокорреляция: {autocorrelation:F4}");
        Console.WriteLine($"  Экспонента Хёрста: {hurstExponent:F4}");
        Console.WriteLine($"  Диапазон: {prices.Min():F2} - {prices.Max():F2}");
        Console.WriteLine();
    }
    
    static double CalculateReturnsVolatility(double[] prices)
    {
        var returns = new double[prices.Length - 1];
        for (int i = 1; i < prices.Length; i++)
        {
            returns[i - 1] = Math.Log(prices[i] / prices[i - 1]);
        }
        double mean = returns.Average();
        double variance = returns.Average(r => Math.Pow(r - mean, 2));
        return Math.Sqrt(variance);
    }
    
    static double CalculateAutocorrelation(double[] prices, int lag)
    {
        if (lag >= prices.Length - 1) return 0;
        
        var returns = new double[prices.Length - 1];
        for (int i = 1; i < prices.Length; i++)
        {
            returns[i - 1] = Math.Log(prices[i] / prices[i - 1]);
        }
        
        double mean = returns.Average();
        double variance = returns.Average(r => Math.Pow(r - mean, 2));
        
        if (variance == 0) return 0;
        
        double covariance = 0;
        for (int i = 0; i < returns.Length - lag; i++)
        {
            covariance += (returns[i] - mean) * (returns[i + lag] - mean);
        }
        covariance /= (returns.Length - lag);
        
        return covariance / variance;
    }
    
    static double EstimateHurstExponent(double[] prices)
    {
        // Упрощенная оценка экспоненты Хёрста
        var returns = prices.Select((p, i) => i > 0 ? Math.Log(p / prices[i - 1]) : 0).Skip(1).ToArray();
        return 0.6 + CalculateAutocorrelation(prices, 1) * 0.4; // Эвристика
    }
    
    static void VisualizePrices(double[] prices, string title)
    {
        Console.WriteLine($"{title}:");
        Console.WriteLine(new string('-', 60));
        
        double min = prices.Min();
        double max = prices.Max();
        int height = 20;
        
        for (int y = height - 1; y >= 0; y--)
        {
            double priceLevel = min + (max - min) * y / height;
            Console.Write($"{priceLevel,8:F1} | ");
            
            for (int x = 0; x < Math.Min(50, prices.Length); x++)
            {
                if (Math.Abs(prices[x] - priceLevel) < (max - min) / height * 0.5)
                    Console.Write("●");
                else
                    Console.Write(" ");
            }
            Console.WriteLine();
        }
        Console.WriteLine(new string('-', 60));
    }
}

Ключевые особенности:

  1. Локальность - цены находятся в определенных диапазонах

  2. Память - текущее значение зависит от предыдущих

  3. Кластеризация волатильности - периоды спокойствия и активности

  4. Режимы рынка - трендовые и флэтовые периоды

  5. Поддержка/сопротивление - отскоки от границ каналов

Теперь генерация будет похожа на реальные котировки! 📈

Комментариев нет:

Отправить комментарий