Вычисление "Max Draw Down" в SQL
edit: стоит рассмотреть раздел комментариев первого ответа, чтобы получить более четкое представление о проблеме.
edit: Я использую SQLServer 2005
что-то похожее на это было опубликовано раньше, но я не думаю, что плакат дал достаточно информации, чтобы по-настоящему объяснить, что такое максимальное сокращение. Все мои определения максимального вытягивания происходят из (первых двух страниц) этой статьи:
http://www.stat.columbia.edu/~vecer/maxdrawdown3.pdf
у вас есть несколько терминов, определенных математически:
Running Maximum, M t
M t= max u в [0, t] (S u)
где S t - цена запаса, S, в момент времени, t.
Просадка, D t
D t= M t - S t
Max Draw Down, MDD t
MDD t= max u в [0, t] (D u)
Таким образом, эффективно то, что нужно определить, - это локальные максимумы и минимумы от набора высоких и низких цен за данный запас в течение определенного периода времени.
У меня есть таблица исторических цитат со следующими (соответствующими) столбцами:
stockid int
day date
hi int --this is in pennies
low int --also in pennies
поэтому для заданного диапазона дат каждый день будет отображаться тот же самый материал для этого диапазона.
EDIT:
hi и low являются высокими для дня и минимума для каждого дня.
после определения локального max и min, вы можете соединить каждый макс с каждым минусом, который приходит после него, и вычислить разницу. Из этого набора максимальной разницей будет "Макс. Ничья вниз".
Жесткая часть, однако, находит те max и min.
edit: следует отметить:
максимальная просадка определяется как величина гипотетической потери, если акция куплена у нее наивысшей точкой покупки и продается на ней с понижением точки продажи. Запасы не могут быть проданы с минимальным значением, которое было до maxval. поэтому, если глобальное значение minval предшествует глобальному maxval, эти два значения не предоставляют достаточной информации для определения максимального просадки.
Ответы
Ответ 1
Некоторые вещи, которые мы должны рассмотреть в проблемной области:
- Акции имеют диапазон цен каждый день, часто просматриваемый в диаграммах подсвечников.
- позволяет вызывать самую высокую цену за день HI
- позволяет вызывать самую низкую цену за день LOW
- проблема ограничена временем, даже если временные ограничения являются датой IPO и датами Delisting
- максимальная просадка - это то, что вы могли бы потерять на складе за это время
- предполагая стратегию LONG: логически, если мы сможем определить все локальные maxes (MAXES) и все локальные mins (MINS), мы могли бы определить набор, где мы свяжем каждый MAX с каждым последующим MIN и вычисляем разницу DIFFS
- Иногда разница приводит к отрицательному числу, однако это не просадка
- поэтому нам нужно выбрать append 0 в наборе diff и выбрать max
Проблема заключается в определении MAXES и MINS, с функцией кривой мы можем применить исчисление, bummer мы не можем. Очевидно,
- максимальные значения должны поступать из HI и
- MINS необходимо исходить от LOW
Один из способов решения этой проблемы - определить курсор и перетащить его. Функциональные языки имеют хорошие инструменты для решения этой проблемы.
Ответ 2
Жестоко неэффективная, но очень простая версия с использованием представления ниже:
WITH DDView
AS (SELECT pd_curr.StockID,
pd_curr.Date,
pd_curr.Low_Price AS CurrPrice,
pd_prev.High_Price AS PrevPrice,
pd_curr.Low_Price / pd_prev.High_Price - 1.0 AS DD
FROM PriceData pd_curr
INNER JOIN PriceData pd_prev
ON pd_curr.StockID = pd_prev.StockID
AND pd_curr.Date >= pd_prev.Date
AND pd_curr.Low_Price <= pd_prev.High_Price
AND pd_prev.Date >= '2001-12-31' -- @param: min_date of analyzed period
WHERE pd_curr.Date <= '2010-09-31' -- @param: max_date of analyzed period
)
SELECT dd.StockID,
MIN(COALESCE(dd.DD, 0)) AS MaxDrawDown
FROM DDView dd
GROUP BY dd.StockID
Как обычно, вы проводите анализ в определенный период времени, имеет смысл обернуть запрос в хранимой процедуре параметрами @StartDate, @EndDate
и, возможно, @StockID
. Опять же, это довольно неэффективно по дизайну - O (N ^ 2), но если у вас хорошие индексы и не огромный объем данных, SQL Server справится с этим довольно неплохо.
Ответ 3
Для SQL Server и для одного запаса за раз, попробуйте следующее:
Create Procedure 'MDDCalc'(
@StartDate date,
@EndDate date,
@Stock int)
AS
DECLARE @MinVal Int
DECLARE @MaxVal Int
DECLARE @MaxDate date
SET @MaxVal = (
SELECT MAX(hi)
FROM Table
WHERE Stockid = @Stock
AND Day BETWEEN (@Startdate-1) AND (@EndDate+1))
SET @MaxDate=(
SELECT Min(Date)
FROM Table
WHERE Stockid = @Stock
AND hi = @MaxVal)
SET @MinVal = (
SELECT MIN(low)
FROM Table
WHERE Stockid = @Stock
AND Day BETWEEN (@MaxDate-1) AND (@EndDate+1))
SELECT (@[email protected]) AS 'MDD'
Ответ 4
Недавно я столкнулся с этой проблемой, Мое решение выглядит так:
данные: 3,5,7,3, -1,3, -8, -3,0,10
добавьте сумму один за другим, если сумма отлична от 0, установите ее 0, иначе получите сумму, результат будет таким, как это
0,0,0,0, -1,0, -8, -11, -11, -1
Максимальное вытягивание - это самое низкое значение в данных, -11.
Ответ 5
Это то, что вам нужно?
select StockID,max(drawdown) maxdrawdown
from (
select h.StockID,h.day highdate,l.day lowdate,h.hi - l.lo drawdown
from mdd h
inner join mdd l on h.StockID = l.StockID
and h.day<l.day) x
group by StockID;
Это основанный на SQL подход грубой силы. Он сравнивает каждую низкую цену после сегодняшнего дня с ценой на одном и том же складе и находит наибольшую разницу между двумя ценами. Это будет максимальный Draw Down.
Нельзя сравнить тот же день, насколько это возможно, для максимального вытягивания, так как у нас недостаточно информации в таблице, чтобы определить, произошла ли цена Hi до цены Lo в день.
Ответ 6
Вот пользовательская функция SQL Server 2005, которая должна очень эффективно возвращать правильный ответ для одного элемента питания.
CREATE FUNCTION dbo.StockMaxDD(@StockID int, @day datetime) RETURNS int AS
BEGIN
Declare @MaxVal int; Set @MaxVal = 0;
Declare @MaxDD int; Set @MaxDD = 0;
SELECT TOP(99999)
@MaxDD = CASE WHEN @MaxDD < (@MaxVal-low) THEN (@MaxVal-low) ELSE @MaxDD END,
@MaxVal = CASE WHEN hi > @MaxVal THEN hi ELSE @MaxVal END
FROM StockHiLo
WHERE stockid = @Stockid
AND [day] <= @day
ORDER BY [day] ASC
RETURN @MaxDD;
END
Это, однако, не будет очень эффективным для одновременного выполнения нескольких запасов. Если вам нужно сделать много/всех запасов сразу, то есть аналогичный, но существенно более сложный подход, который может сделать это очень эффективно.