Q : Как улучшить производительность следующей реализации?
Векторизованная обработка?
Это часть немного загадочная - простите старый квант, чтобы он не читал это достаточно хорошо - информация о том, какие параметры были предназначены, чтобы не быть скаляром, отсутствовала, поэтому анализ был основан на явно представленных фрагментах информации.
Отказ от ответственности :
Хотя я знаю, что DolphinDB не опубликовал троичный оператор (...)?(...):(...)
, который был бы доступен в API publi c, я чувствую, что идеи, изложенные ниже, ясны и Звук.
Боевая производительность?
Если серьезно говорить о производительности, сначала давайте рассмотрим и принципиально избежим повторных пересчетов, которые имели место в предложенном выше коде:
def GBlackScholes( future_price,
strike,
input_ttm,
risk_rate,
b_rate,
input_vol, // <------------[VAR]:: <-- ( high+low )/2
is_call //
) { //
ttm = input_ttm + 0.000000000000001; //-do-while-(CONST)
vol = input_vol + 0.000000000000001;//--do-while--------[VAR]
//
d1 = ( log( future_price ) //----do-while-(CONST)
- log( strike ) //-----do-while-(CONST)
+ b_rate //------do-while-(CONST)
+ vol*vol/2 //-------do-while--------[VAR]
* ttm //--------do-while-(CONST)
) / ( vol //---------do-while--------[VAR]
* sqrt( ttm ) //----------do-while-(CONST)
); //
d2 = ( d1 //------------do-while--------[VAR]
- vol //-------------do-while--------[VAR]
* sqrt( ttm ) //--------------do-while-(CONST)
); // ++---------------[VAR]
// || .________________________________________________.
// -----------[VAR]-?-( cdfNormal(--------vv-) * [ ]--do-while-(CONST)
return ( is_call ? ( cdfNormal( 0, 1, d1 ) * future_price * exp( ( b_rate - risk_rate ) * ttm )
- cdfNormal( 0, 1, d2 ) * strike * exp( -risk_rate * ttm )
)
: ( cdfNormal( 0, 1, -d2 ) * strike * exp( -risk_rate * ttm )
- cdfNormal( 0, 1, -d1 ) * future_price * exp( ( b_rate - risk_rate ) * ttm )
)
);
}
Чуть лучше сформулированная GBlackScholes_WHILEd()
функция - это экономит ~ 22x
float
-OP (некоторые из которых довольно дорогие) для каждого * 10 31 * -L OOP:
def GBlackScholes_WHILEd( vol_, // <--------------------------[VAR]:: ( high+low )/2 + 0.000000000000001;
V1, // <--------------------------[VAR]:: vol_ * C3
is_call,
ttm_, // do-while-(CONST)
C1, C2, C3, // do-while-(CONST)
R1, R2 // do-while-(CONST)
) {
d1 = ( C1
+ C2
* vol_*vol_ //--------------------do-while--------[VAR]
)
/ V1; //--------------------do-while--------[VAR]
d2 = ( d1 //---------------------------do-while--------[VAR]
- V1 //---------------------------do-while--------[VAR]
);
// --[VAR]--- ? ( cdfNormal(------[VAR]) * <________________________________________________>--do-while-(CONST)
return ( is_call ? ( cdfNormal( 0, 1, d1 ) * R1
- cdfNormal( 0, 1, d2 ) * R2
)
: ( cdfNormal( 0, 1, -d2 ) * R2
- cdfNormal( 0, 1, -d1 ) * R1
)
);
}
Наконец:
Наиболее эффективно сформулированная функция ImpliedVolatility()
позволяет избежать даже всех вызовов-подписей в -l oop вообще обработал, выполнил некоторую алгебру и остается на достижимом крае производительности:
def ImpliedVolatility( future_price,
strike,
ttm,
risk_rate,
b_rate,
option_price,
is_call
) {
high = 5.0; // IS THIS A UNIVERSALLY SAFE & TRUE SUPREME - i.e. SAFELY ABOVE ALL POSSIBLE OPTIONS ?
low = 0.0;
ttm_ = ttm + 0.000000000000001; // do-while-(CONST) 1x fADD
C1 = log(future_price ) - log( strike ) + b_rate; // do-while-(CONST) 1x fADD 1x fDIV 1x fLOG 1x fNEG
C2 = ( ttm_ ) / 2; // do-while-(CONST) 1x fDIV
C3 = sqrt( ttm_ ); // do-while-(CONST) 1x fSQRT
R1 = future_price * exp( ( b_rate - risk_rate ) * ttm_ ); // do-while-(CONST) 1x fADD 2x fMUL 1x fEXP 1x fNEG
R2 = strike * exp( -risk_rate * ttm_ ); // do-while-(CONST) 2x fMUL 1x fEXP 1x fNEG
U4 = C2 - ttm_; // do-while-(CONST) 1x fADD 1x fNEG
U5 = ttm_ - C2; // do-while-(CONST) 1x fADD 1x fNEG
U3inv= 1./ C3; // do-while-(CONST) 1x fDIV
// ------------------------------------------------------------// -----------------------------------------------------------------------------------------------
if ( is_call ) { // do-while-RE-TESTING: AVOIDED REPETITIVE per-loop COSTS of TESTING THE VERY THE SAME
// -----------------------------------------------------------------------------------------------
do {
mid = ( high + low ) / 2; // cheapest do-while per-loop-[VAR]-update
vol_ = mid + 0.000000000000001; // cheapest do-while per-loop-[VAR]-update
vol_2 = vol_ * vol_; // cheapest do-while per-loop-[VAR]-update
/* ---------------------------------------------------------------------------------------------------------------------------------------------
HAS EVOLVED FROM THE ORIGINAL FORMULATION + AVOIDED REPETITIVE per-loop COSTS of 20+ expensive float OPs fully wasted,all in do-while-(CONST)
+ AVOIDED REPETITIVE per-loop COSTS of all the CALL fun() STACK MANIPULATIONS AND RELATED OVERHEADS
---------------------------------------------------------------------------------------------------------------------------------------------
*/
// V4d1 = ( C1 + C2 * vol_2 ) / vol_ / C3; // [VAR]-dependent updates per loop
// V5d2 = ( C1 + ( C2 - ttm_ ) * vol_2 ) / vol_ / C3; // [VAR]-dependent updates per loop
// Vmd2 = ( ( ttm_ - C2 ) * vol_2 - C1 ) / vol_ / C3; // [VAR]-dependent updates per loop
//
// V4d1 = U3inv * ( C1 + C2 * vol_2 ) / vol_; // fMUL faster than fDIV + a few more fUtilityCONSTs
// V5d2 = U3inv * ( C1 + U4 * vol_2 ) / vol_; // fMUL faster than fDIV + a few more fUtilityCONSTs
// Vmd2 = U3inv * ( U5 * vol_2 - C1 ) / vol_; // fMUL faster than fDIV + a few more fUtilityCONSTs
//
// ---------------------------------------------------------------------------------------------------
// THIS AVOIDS RE-CALCULATION OF ALL do-while-(CONST)s BY THEIR RE-USE :
//
// if ( option_price < GBlackScholes_WHILEd( vol_, // <----------[VAR] input_vol, // GBlackScholes( future_price,
// vol_ * C3, // <----------[VAR] V1, // strike,
// is_call, // is_call, // ttm,
// ttm_, // do-while-(CONST) ttm_, // risk_rate,
// C1, C2, C3, // do-while-(CONST) C1, C2, C3, // b_rate,
// R1, R2 // do-while-(CONST) R1, R2 // mid, // == (high+low)/2,
// ) // // is_call
// ) ... // // )
//
// --------------------------------------------------------------------------------------------------
// EVEN BETTER :
//
// if ( option_price < ( is_call ? ( R1 * cdfNormal( 0, 1, U3inv * ( C1 + C2 * vol_2 ) / vol_ )
// - R2 * cdfNormal( 0, 1, U3inv * ( C1 + U4 * vol_2 ) / vol_ )
// )
// : ( R2 * cdfNormal( 0, 1, U3inv * ( U5 * vol_2 - C1 ) / vol_ )
// - R1 * cdfNormal( 0, 1, -U3inv * ( C1 + C2 * vol_2 ) / vol_ )
// )
// )
//
// ) ...
// ________________________________( CALL-OPTIONs )__________________________________________________
if ( option_price < ( ( R1 * cdfNormal( 0, 1, U3inv * ( C1 + C2 * vol_2 ) / vol_ )
- R2 * cdfNormal( 0, 1, U3inv * ( C1 + U4 * vol_2 ) / vol_ )
)
)
) { high = mid; // == (high+low)/2; // LOWER HI-SIDE BRACKET
} else { low = mid; // == (high+low)/2; // HEIGHTEN LO-SIDE BRACKET
}
} while ( ( high - low ) > 0.00001 );
return ( high + low ) / 2; // ________________________________________________________________ JIT/RET
} else {
do { mid = ( high + low ) / 2; // cheapest do-while per-loop-[VAR]-update
vol_ = mid + 0.000000000000001; // cheapest do-while per-loop-[VAR]-update
vol_2 = vol_ * vol_; // cheapest do-while per-loop-[VAR]-update
// ________________________________( PUT-OPTIONs )___________________________________________________
if ( option_price < ( ( R2 * cdfNormal( 0, 1, U3inv * ( U5 * vol_2 - C1 ) / vol_ )
- R1 * cdfNormal( 0, 1, -U3inv * ( C1 + C2 * vol_2 ) / vol_ )
)
)
) { high = mid; // == (high+low)/2; // LOWER HI-SIDE BRACKET
} else { low = mid; // == (high+low)/2; // HEIGHTEN LO-SIDE BRACKET
}
} while ( ( high - low ) > 0.00001 );
return ( high + low ) / 2; // ________________________________________________________________ JIT/RET
}
}