| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594459545964597459845994600460146024603460446054606460746084609461046114612461346144615461646174618461946204621462246234624462546264627462846294630463146324633463446354636463746384639464046414642464346444645464646474648464946504651465246534654465546564657465846594660466146624663466446654666466746684669467046714672467346744675467646774678467946804681468246834684468546864687468846894690469146924693469446954696469746984699470047014702470347044705470647074708470947104711471247134714471547164717471847194720472147224723472447254726472747284729473047314732473347344735473647374738473947404741474247434744474547464747474847494750475147524753475447554756475747584759476047614762476347644765476647674768476947704771477247734774477547764777477847794780478147824783478447854786478747884789479047914792479347944795479647974798479948004801480248034804480548064807480848094810481148124813481448154816481748184819482048214822482348244825482648274828482948304831483248334834483548364837483848394840484148424843484448454846484748484849485048514852485348544855485648574858485948604861486248634864486548664867486848694870487148724873487448754876487748784879488048814882488348844885488648874888488948904891489248934894489548964897489848994900490149024903490449054906490749084909491049114912491349144915491649174918491949204921492249234924492549264927492849294930493149324933493449354936493749384939494049414942494349444945494649474948494949504951495249534954495549564957495849594960496149624963496449654966496749684969497049714972497349744975497649774978497949804981498249834984498549864987498849894990499149924993499449954996499749984999500050015002500350045005500650075008500950105011501250135014501550165017501850195020502150225023502450255026502750285029503050315032503350345035503650375038503950405041504250435044504550465047504850495050505150525053505450555056505750585059506050615062506350645065506650675068506950705071507250735074507550765077507850795080508150825083508450855086508750885089509050915092509350945095509650975098509951005101510251035104510551065107510851095110511151125113511451155116511751185119512051215122512351245125512651275128512951305131513251335134513551365137513851395140514151425143514451455146514751485149515051515152515351545155515651575158515951605161516251635164516551665167516851695170517151725173517451755176517751785179518051815182518351845185518651875188518951905191519251935194519551965197519851995200520152025203520452055206520752085209521052115212521352145215521652175218521952205221522252235224522552265227522852295230523152325233523452355236523752385239524052415242524352445245524652475248524952505251525252535254525552565257525852595260526152625263526452655266526752685269527052715272527352745275527652775278527952805281528252835284528552865287528852895290529152925293529452955296529752985299530053015302530353045305530653075308530953105311531253135314531553165317531853195320532153225323532453255326532753285329533053315332533353345335533653375338533953405341534253435344534553465347534853495350535153525353535453555356535753585359536053615362536353645365536653675368536953705371537253735374537553765377537853795380538153825383538453855386538753885389539053915392539353945395539653975398539954005401540254035404540554065407540854095410541154125413541454155416541754185419542054215422542354245425542654275428542954305431543254335434543554365437543854395440544154425443544454455446544754485449545054515452545354545455545654575458545954605461546254635464546554665467546854695470547154725473547454755476547754785479548054815482548354845485548654875488548954905491549254935494549554965497549854995500550155025503550455055506550755085509551055115512551355145515551655175518551955205521552255235524552555265527552855295530553155325533553455355536553755385539554055415542554355445545554655475548554955505551555255535554555555565557555855595560556155625563556455655566556755685569557055715572557355745575557655775578557955805581558255835584558555865587558855895590559155925593559455955596559755985599560056015602560356045605560656075608560956105611561256135614561556165617561856195620562156225623562456255626562756285629563056315632563356345635563656375638563956405641564256435644564556465647564856495650565156525653565456555656565756585659566056615662566356645665566656675668566956705671567256735674567556765677567856795680568156825683568456855686568756885689569056915692569356945695569656975698569957005701570257035704570557065707570857095710571157125713571457155716571757185719572057215722572357245725572657275728572957305731573257335734573557365737573857395740574157425743574457455746574757485749575057515752575357545755575657575758575957605761576257635764576557665767576857695770577157725773577457755776577757785779578057815782578357845785578657875788578957905791579257935794579557965797579857995800580158025803580458055806580758085809581058115812581358145815581658175818581958205821582258235824582558265827582858295830583158325833583458355836583758385839584058415842584358445845584658475848584958505851585258535854585558565857585858595860586158625863586458655866586758685869587058715872587358745875587658775878587958805881588258835884588558865887588858895890589158925893589458955896589758985899590059015902590359045905590659075908590959105911591259135914591559165917591859195920592159225923592459255926592759285929593059315932593359345935593659375938593959405941594259435944594559465947594859495950595159525953595459555956595759585959596059615962596359645965596659675968596959705971597259735974597559765977597859795980598159825983598459855986598759885989599059915992599359945995599659975998599960006001600260036004600560066007600860096010601160126013601460156016601760186019602060216022602360246025602660276028602960306031603260336034603560366037603860396040604160426043604460456046604760486049605060516052605360546055605660576058605960606061606260636064606560666067606860696070607160726073607460756076607760786079608060816082608360846085608660876088608960906091609260936094609560966097609860996100610161026103610461056106610761086109611061116112611361146115611661176118611961206121612261236124612561266127612861296130613161326133613461356136613761386139614061416142614361446145614661476148614961506151615261536154615561566157615861596160616161626163616461656166616761686169617061716172617361746175617661776178617961806181618261836184618561866187618861896190619161926193619461956196619761986199620062016202620362046205620662076208620962106211621262136214621562166217621862196220622162226223622462256226622762286229623062316232623362346235623662376238623962406241624262436244624562466247624862496250625162526253625462556256625762586259626062616262626362646265626662676268626962706271627262736274627562766277627862796280628162826283628462856286628762886289629062916292629362946295629662976298629963006301630263036304630563066307630863096310631163126313631463156316631763186319632063216322632363246325632663276328632963306331633263336334633563366337633863396340634163426343634463456346634763486349635063516352635363546355635663576358635963606361636263636364636563666367636863696370637163726373637463756376637763786379638063816382638363846385638663876388638963906391639263936394639563966397639863996400640164026403640464056406640764086409641064116412641364146415641664176418641964206421642264236424642564266427642864296430643164326433643464356436643764386439644064416442644364446445644664476448644964506451645264536454645564566457645864596460646164626463646464656466646764686469647064716472647364746475647664776478647964806481648264836484648564866487648864896490649164926493649464956496649764986499650065016502650365046505650665076508650965106511651265136514651565166517651865196520652165226523652465256526652765286529653065316532653365346535653665376538653965406541654265436544654565466547654865496550655165526553655465556556655765586559656065616562656365646565656665676568656965706571657265736574657565766577657865796580658165826583658465856586658765886589659065916592659365946595659665976598659966006601660266036604660566066607660866096610661166126613661466156616661766186619662066216622662366246625662666276628662966306631663266336634663566366637663866396640664166426643664466456646664766486649665066516652665366546655665666576658665966606661666266636664666566666667666866696670667166726673667466756676667766786679668066816682668366846685668666876688668966906691669266936694669566966697669866996700670167026703670467056706670767086709671067116712671367146715671667176718671967206721672267236724672567266727672867296730673167326733673467356736673767386739674067416742674367446745674667476748674967506751675267536754675567566757675867596760676167626763676467656766676767686769677067716772677367746775677667776778677967806781678267836784678567866787678867896790679167926793679467956796679767986799680068016802680368046805680668076808680968106811681268136814681568166817681868196820682168226823682468256826682768286829683068316832683368346835683668376838683968406841684268436844684568466847684868496850685168526853685468556856685768586859686068616862686368646865686668676868686968706871687268736874687568766877687868796880688168826883688468856886688768886889689068916892689368946895689668976898689969006901690269036904690569066907690869096910691169126913691469156916691769186919692069216922692369246925692669276928692969306931693269336934693569366937693869396940694169426943694469456946694769486949695069516952695369546955695669576958695969606961696269636964696569666967696869696970697169726973697469756976697769786979698069816982698369846985698669876988698969906991699269936994699569966997699869997000700170027003700470057006700770087009701070117012701370147015701670177018701970207021702270237024702570267027702870297030703170327033703470357036703770387039704070417042704370447045704670477048704970507051705270537054705570567057705870597060706170627063706470657066706770687069707070717072707370747075707670777078707970807081708270837084708570867087708870897090709170927093709470957096709770987099710071017102710371047105710671077108710971107111711271137114711571167117711871197120712171227123712471257126712771287129713071317132713371347135713671377138713971407141714271437144714571467147714871497150715171527153715471557156715771587159716071617162716371647165716671677168716971707171717271737174717571767177717871797180718171827183718471857186718771887189719071917192719371947195719671977198719972007201720272037204720572067207720872097210721172127213721472157216721772187219722072217222722372247225722672277228722972307231723272337234723572367237723872397240724172427243724472457246724772487249725072517252725372547255725672577258725972607261726272637264726572667267726872697270727172727273727472757276727772787279728072817282728372847285728672877288728972907291729272937294729572967297729872997300730173027303730473057306730773087309731073117312731373147315731673177318731973207321732273237324732573267327732873297330733173327333733473357336733773387339734073417342734373447345734673477348734973507351735273537354735573567357735873597360736173627363736473657366736773687369737073717372737373747375737673777378737973807381738273837384738573867387738873897390739173927393739473957396739773987399740074017402740374047405740674077408740974107411741274137414741574167417741874197420742174227423742474257426742774287429743074317432743374347435743674377438743974407441744274437444744574467447744874497450745174527453745474557456745774587459746074617462746374647465746674677468746974707471747274737474747574767477747874797480748174827483748474857486748774887489749074917492749374947495749674977498749975007501750275037504750575067507750875097510751175127513751475157516751775187519752075217522752375247525752675277528752975307531753275337534753575367537753875397540754175427543754475457546754775487549755075517552755375547555755675577558755975607561756275637564756575667567756875697570757175727573757475757576757775787579758075817582758375847585758675877588758975907591759275937594759575967597759875997600760176027603760476057606760776087609761076117612761376147615761676177618761976207621762276237624762576267627762876297630763176327633763476357636763776387639764076417642764376447645764676477648764976507651765276537654765576567657765876597660766176627663766476657666766776687669767076717672767376747675767676777678767976807681768276837684768576867687768876897690769176927693769476957696769776987699770077017702770377047705770677077708770977107711771277137714771577167717771877197720772177227723772477257726772777287729773077317732773377347735773677377738773977407741774277437744774577467747774877497750775177527753775477557756775777587759776077617762776377647765776677677768776977707771777277737774777577767777777877797780778177827783778477857786778777887789779077917792779377947795779677977798779978007801780278037804780578067807780878097810781178127813781478157816781778187819782078217822782378247825782678277828782978307831783278337834783578367837783878397840784178427843784478457846784778487849785078517852785378547855785678577858785978607861786278637864786578667867786878697870787178727873787478757876787778787879788078817882788378847885788678877888788978907891789278937894789578967897789878997900790179027903790479057906790779087909791079117912791379147915791679177918791979207921792279237924792579267927792879297930793179327933793479357936793779387939794079417942794379447945794679477948794979507951795279537954795579567957795879597960796179627963796479657966796779687969797079717972797379747975797679777978797979807981798279837984798579867987798879897990799179927993799479957996799779987999800080018002800380048005800680078008800980108011801280138014801580168017801880198020802180228023802480258026802780288029803080318032803380348035803680378038803980408041804280438044804580468047804880498050805180528053805480558056805780588059806080618062806380648065806680678068806980708071807280738074807580768077807880798080808180828083808480858086808780888089809080918092809380948095809680978098809981008101810281038104810581068107810881098110811181128113811481158116811781188119812081218122812381248125812681278128812981308131813281338134813581368137813881398140814181428143814481458146814781488149815081518152815381548155815681578158815981608161816281638164816581668167816881698170817181728173817481758176817781788179818081818182818381848185818681878188818981908191819281938194819581968197819881998200820182028203820482058206820782088209821082118212821382148215821682178218821982208221822282238224822582268227822882298230823182328233823482358236823782388239824082418242824382448245824682478248824982508251825282538254825582568257825882598260826182628263826482658266826782688269827082718272827382748275827682778278827982808281828282838284828582868287828882898290829182928293829482958296829782988299830083018302830383048305830683078308830983108311831283138314831583168317831883198320832183228323832483258326832783288329833083318332833383348335833683378338833983408341834283438344834583468347834883498350835183528353835483558356835783588359836083618362836383648365836683678368836983708371837283738374837583768377837883798380838183828383838483858386838783888389839083918392839383948395839683978398839984008401840284038404840584068407840884098410841184128413841484158416841784188419842084218422842384248425842684278428842984308431843284338434843584368437843884398440844184428443844484458446844784488449845084518452845384548455845684578458845984608461846284638464846584668467846884698470847184728473847484758476847784788479848084818482848384848485848684878488848984908491849284938494849584968497849884998500850185028503850485058506850785088509851085118512851385148515851685178518851985208521852285238524852585268527852885298530853185328533853485358536853785388539854085418542854385448545854685478548854985508551855285538554855585568557855885598560856185628563856485658566856785688569857085718572857385748575857685778578857985808581858285838584858585868587858885898590859185928593859485958596859785988599860086018602860386048605860686078608860986108611861286138614861586168617861886198620862186228623862486258626862786288629863086318632863386348635863686378638863986408641864286438644864586468647864886498650865186528653865486558656865786588659866086618662866386648665866686678668866986708671867286738674867586768677867886798680 |
- /**
- * @license Highstock JS v8.2.0 (2020-08-20)
- *
- * All technical indicators for Highstock
- *
- * (c) 2010-2019 Pawel Fus
- *
- * License: www.highcharts.com/license
- */
- 'use strict';
- (function (factory) {
- if (typeof module === 'object' && module.exports) {
- factory['default'] = factory;
- module.exports = factory;
- } else if (typeof define === 'function' && define.amd) {
- define('highcharts/indicators/indicators-all', ['highcharts', 'highcharts/modules/stock'], function (Highcharts) {
- factory(Highcharts);
- factory.Highcharts = Highcharts;
- return factory;
- });
- } else {
- factory(typeof Highcharts !== 'undefined' ? Highcharts : undefined);
- }
- }(function (Highcharts) {
- var _modules = Highcharts ? Highcharts._modules : {};
- function _registerModule(obj, path, args, fn) {
- if (!obj.hasOwnProperty(path)) {
- obj[path] = fn.apply(null, args);
- }
- }
- _registerModule(_modules, 'Mixins/IndicatorRequired.js', [_modules['Core/Utilities.js']], function (U) {
- /**
- *
- * (c) 2010-2020 Daniel Studencki
- *
- * License: www.highcharts.com/license
- *
- * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
- *
- * */
- var error = U.error;
- /* eslint-disable no-invalid-this, valid-jsdoc */
- var requiredIndicatorMixin = {
- /**
- * Check whether given indicator is loaded,
- else throw error.
- * @private
- * @param {Highcharts.Indicator} indicator
- * Indicator constructor function.
- * @param {string} requiredIndicator
- * Required indicator type.
- * @param {string} type
- * Type of indicator where function was called (parent).
- * @param {Highcharts.IndicatorCallbackFunction} callback
- * Callback which is triggered if the given indicator is loaded.
- * Takes indicator as an argument.
- * @param {string} errMessage
- * Error message that will be logged in console.
- * @return {boolean}
- * Returns false when there is no required indicator loaded.
- */
- isParentLoaded: function (indicator,
- requiredIndicator,
- type,
- callback,
- errMessage) {
- if (indicator) {
- return callback ? callback(indicator) : true;
- }
- error(errMessage || this.generateMessage(type, requiredIndicator));
- return false;
- },
- /**
- * @private
- * @param {string} indicatorType
- * Indicator type
- * @param {string} required
- * Required indicator
- * @return {string}
- * Error message
- */
- generateMessage: function (indicatorType, required) {
- return 'Error: "' + indicatorType +
- '" indicator type requires "' + required +
- '" indicator loaded before. Please read docs: ' +
- 'https://api.highcharts.com/highstock/plotOptions.' +
- indicatorType;
- }
- };
- return requiredIndicatorMixin;
- });
- _registerModule(_modules, 'Stock/Indicators/Indicators.js', [_modules['Core/Globals.js'], _modules['Mixins/IndicatorRequired.js'], _modules['Core/Utilities.js']], function (H, requiredIndicator, U) {
- /* *
- *
- * License: www.highcharts.com/license
- *
- * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
- *
- * */
- var addEvent = U.addEvent,
- error = U.error,
- extend = U.extend,
- isArray = U.isArray,
- pick = U.pick,
- seriesType = U.seriesType,
- splat = U.splat;
- var Series = H.Series,
- seriesTypes = H.seriesTypes,
- ohlcProto = H.seriesTypes.ohlc.prototype,
- generateMessage = requiredIndicator.generateMessage;
- /**
- * The parameter allows setting line series type and use OHLC indicators. Data
- * in OHLC format is required.
- *
- * @sample {highstock} stock/indicators/use-ohlc-data
- * Plot line on Y axis
- *
- * @type {boolean}
- * @product highstock
- * @apioption plotOptions.line.useOhlcData
- */
- /* eslint-disable no-invalid-this */
- addEvent(H.Series, 'init', function (eventOptions) {
- var series = this,
- options = eventOptions.options;
- if (options.useOhlcData &&
- options.id !== 'highcharts-navigator-series') {
- extend(series, {
- pointValKey: ohlcProto.pointValKey,
- keys: ohlcProto.keys,
- pointArrayMap: ohlcProto.pointArrayMap,
- toYData: ohlcProto.toYData
- });
- }
- });
- addEvent(Series, 'afterSetOptions', function (e) {
- var options = e.options,
- dataGrouping = options.dataGrouping;
- if (dataGrouping &&
- options.useOhlcData &&
- options.id !== 'highcharts-navigator-series') {
- dataGrouping.approximation = 'ohlc';
- }
- });
- /* eslint-enable no-invalid-this */
- /**
- * The SMA series type.
- *
- * @private
- * @class
- * @name Highcharts.seriesTypes.sma
- *
- * @augments Highcharts.Series
- */
- seriesType('sma', 'line',
- /**
- * Simple moving average indicator (SMA). This series requires `linkedTo`
- * option to be set.
- *
- * @sample stock/indicators/sma
- * Simple moving average indicator
- *
- * @extends plotOptions.line
- * @since 6.0.0
- * @excluding allAreas, colorAxis, dragDrop, joinBy, keys,
- * navigatorOptions, pointInterval, pointIntervalUnit,
- * pointPlacement, pointRange, pointStart, showInNavigator,
- * stacking, useOhlcData
- * @product highstock
- * @requires stock/indicators/indicators
- * @optionparent plotOptions.sma
- */
- {
- /**
- * The name of the series as shown in the legend, tooltip etc. If not
- * set, it will be based on a technical indicator type and default
- * params.
- *
- * @type {string}
- */
- name: void 0,
- tooltip: {
- /**
- * Number of decimals in indicator series.
- */
- valueDecimals: 4
- },
- /**
- * The main series ID that indicator will be based on. Required for this
- * indicator.
- *
- * @type {string}
- */
- linkedTo: void 0,
- /**
- * Whether to compare indicator to the main series values
- * or indicator values.
- *
- * @sample {highstock} stock/plotoptions/series-comparetomain/
- * Difference between comparing SMA values to the main series
- * and its own values.
- *
- * @type {boolean}
- */
- compareToMain: false,
- /**
- * Paramters used in calculation of regression series' points.
- */
- params: {
- /**
- * The point index which indicator calculations will base. For
- * example using OHLC data, index=2 means the indicator will be
- * calculated using Low values.
- */
- index: 0,
- /**
- * The base period for indicator calculations. This is the number of
- * data points which are taken into account for the indicator
- * calculations.
- */
- period: 14
- }
- },
- /**
- * @lends Highcharts.Series.prototype
- */
- {
- processData: function () {
- var series = this,
- compareToMain = series.options.compareToMain,
- linkedParent = series.linkedParent;
- Series.prototype.processData.apply(series, arguments);
- if (linkedParent && linkedParent.compareValue && compareToMain) {
- series.compareValue = linkedParent.compareValue;
- }
- return;
- },
- bindTo: {
- series: true,
- eventName: 'updatedData'
- },
- hasDerivedData: true,
- useCommonDataGrouping: true,
- nameComponents: ['period'],
- nameSuffixes: [],
- calculateOn: 'init',
- // Defines on which other indicators is this indicator based on.
- requiredIndicators: [],
- requireIndicators: function () {
- var obj = {
- allLoaded: true
- };
- // Check whether all required indicators are loaded, else return
- // the object with missing indicator's name.
- this.requiredIndicators.forEach(function (indicator) {
- if (seriesTypes[indicator]) {
- seriesTypes[indicator].prototype.requireIndicators();
- }
- else {
- obj.allLoaded = false;
- obj.needed = indicator;
- }
- });
- return obj;
- },
- init: function (chart, options) {
- var indicator = this,
- requiredIndicators = indicator.requireIndicators();
- // Check whether all required indicators are loaded.
- if (!requiredIndicators.allLoaded) {
- return error(generateMessage(indicator.type, requiredIndicators.needed));
- }
- Series.prototype.init.call(indicator, chart, options);
- // Make sure we find series which is a base for an indicator
- chart.linkSeries();
- indicator.dataEventsToUnbind = [];
- /**
- * @private
- * @return {void}
- */
- function recalculateValues() {
- var oldData = indicator.points || [],
- oldDataLength = (indicator.xData || []).length,
- processedData = indicator.getValues(indicator.linkedParent,
- indicator.options.params) || {
- values: [],
- xData: [],
- yData: []
- },
- croppedDataValues = [],
- overwriteData = true,
- oldFirstPointIndex,
- oldLastPointIndex,
- croppedData,
- min,
- max,
- i;
- // We need to update points to reflect changes in all,
- // x and y's, values. However, do it only for non-grouped
- // data - grouping does it for us (#8572)
- if (oldDataLength &&
- !indicator.hasGroupedData &&
- indicator.visible &&
- indicator.points) {
- // When data is cropped update only avaliable points (#9493)
- if (indicator.cropped) {
- if (indicator.xAxis) {
- min = indicator.xAxis.min;
- max = indicator.xAxis.max;
- }
- croppedData = indicator.cropData(processedData.xData, processedData.yData, min, max);
- for (i = 0; i < croppedData.xData.length; i++) {
- // (#10774)
- croppedDataValues.push([
- croppedData.xData[i]
- ].concat(splat(croppedData.yData[i])));
- }
- oldFirstPointIndex = processedData.xData.indexOf(indicator.xData[0]);
- oldLastPointIndex = processedData.xData.indexOf(indicator.xData[indicator.xData.length - 1]);
- // Check if indicator points should be shifted (#8572)
- if (oldFirstPointIndex === -1 &&
- oldLastPointIndex === processedData.xData.length - 2) {
- if (croppedDataValues[0][0] === oldData[0].x) {
- croppedDataValues.shift();
- }
- }
- indicator.updateData(croppedDataValues);
- // Omit addPoint() and removePoint() cases
- }
- else if (processedData.xData.length !== oldDataLength - 1 &&
- processedData.xData.length !== oldDataLength + 1) {
- overwriteData = false;
- indicator.updateData(processedData.values);
- }
- }
- if (overwriteData) {
- indicator.xData = processedData.xData;
- indicator.yData = processedData.yData;
- indicator.options.data = processedData.values;
- }
- // Removal of processedXData property is required because on
- // first translate processedXData array is empty
- if (indicator.bindTo.series === false) {
- delete indicator.processedXData;
- indicator.isDirty = true;
- indicator.redraw();
- }
- indicator.isDirtyData = false;
- }
- if (!indicator.linkedParent) {
- return error('Series ' +
- indicator.options.linkedTo +
- ' not found! Check `linkedTo`.', false, chart);
- }
- indicator.dataEventsToUnbind.push(addEvent(indicator.bindTo.series ?
- indicator.linkedParent : indicator.linkedParent.xAxis, indicator.bindTo.eventName, recalculateValues));
- if (indicator.calculateOn === 'init') {
- recalculateValues();
- }
- else {
- var unbinder = addEvent(indicator.chart,
- indicator.calculateOn,
- function () {
- recalculateValues();
- // Call this just once, on init
- unbinder();
- });
- }
- return indicator;
- },
- getName: function () {
- var name = this.name,
- params = [];
- if (!name) {
- (this.nameComponents || []).forEach(function (component, index) {
- params.push(this.options.params[component] +
- pick(this.nameSuffixes[index], ''));
- }, this);
- name = (this.nameBase || this.type.toUpperCase()) +
- (this.nameComponents ? ' (' + params.join(', ') + ')' : '');
- }
- return name;
- },
- getValues: function (series, params) {
- var period = params.period,
- xVal = series.xData,
- yVal = series.yData,
- yValLen = yVal.length,
- range = 0,
- sum = 0,
- SMA = [],
- xData = [],
- yData = [],
- index = -1,
- i,
- SMAPoint;
- if (xVal.length < period) {
- return;
- }
- // Switch index for OHLC / Candlestick / Arearange
- if (isArray(yVal[0])) {
- index = params.index ? params.index : 0;
- }
- // Accumulate first N-points
- while (range < period - 1) {
- sum += index < 0 ? yVal[range] : yVal[range][index];
- range++;
- }
- // Calculate value one-by-one for each period in visible data
- for (i = range; i < yValLen; i++) {
- sum += index < 0 ? yVal[i] : yVal[i][index];
- SMAPoint = [xVal[i], sum / period];
- SMA.push(SMAPoint);
- xData.push(SMAPoint[0]);
- yData.push(SMAPoint[1]);
- sum -= (index < 0 ?
- yVal[i - range] :
- yVal[i - range][index]);
- }
- return {
- values: SMA,
- xData: xData,
- yData: yData
- };
- },
- destroy: function () {
- this.dataEventsToUnbind.forEach(function (unbinder) {
- unbinder();
- });
- Series.prototype.destroy.apply(this, arguments);
- }
- });
- /**
- * A `SMA` series. If the [type](#series.sma.type) option is not specified, it
- * is inherited from [chart.type](#chart.type).
- *
- * @extends series,plotOptions.sma
- * @since 6.0.0
- * @product highstock
- * @excluding dataParser, dataURL, useOhlcData
- * @requires stock/indicators/indicators
- * @apioption series.sma
- */
- ''; // adds doclet above to the transpiled file
- });
- _registerModule(_modules, 'Stock/Indicators/ADIndicator.js', [_modules['Core/Utilities.js']], function (U) {
- /* *
- *
- * License: www.highcharts.com/license
- *
- * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
- * */
- var error = U.error,
- seriesType = U.seriesType;
- /* eslint-disable valid-jsdoc */
- // Utils:
- /**
- * @private
- */
- function populateAverage(xVal, yVal, yValVolume, i) {
- var high = yVal[i][1],
- low = yVal[i][2],
- close = yVal[i][3],
- volume = yValVolume[i],
- adY = close === high && close === low || high === low ?
- 0 :
- ((2 * close - low - high) / (high - low)) * volume,
- adX = xVal[i];
- return [adX, adY];
- }
- /* eslint-enable valid-jsdoc */
- /**
- * The AD series type.
- *
- * @private
- * @class
- * @name Highcharts.seriesTypes.ad
- *
- * @augments Highcharts.Series
- */
- seriesType('ad', 'sma',
- /**
- * Accumulation Distribution (AD). This series requires `linkedTo` option to
- * be set.
- *
- * @sample stock/indicators/accumulation-distribution
- * Accumulation/Distribution indicator
- *
- * @extends plotOptions.sma
- * @since 6.0.0
- * @product highstock
- * @requires stock/indicators/indicators
- * @requires stock/indicators/accumulation-distribution
- * @optionparent plotOptions.ad
- */
- {
- params: {
- /**
- * The id of volume series which is mandatory.
- * For example using OHLC data, volumeSeriesID='volume' means
- * the indicator will be calculated using OHLC and volume values.
- *
- * @since 6.0.0
- */
- volumeSeriesID: 'volume'
- }
- },
- /**
- * @lends Highcharts.Series#
- */
- {
- nameComponents: false,
- nameBase: 'Accumulation/Distribution',
- getValues: function (series, params) {
- var period = params.period,
- xVal = series.xData,
- yVal = series.yData,
- volumeSeriesID = params.volumeSeriesID,
- volumeSeries = series.chart.get(volumeSeriesID),
- yValVolume = volumeSeries && volumeSeries.yData,
- yValLen = yVal ? yVal.length : 0,
- AD = [],
- xData = [],
- yData = [],
- len,
- i,
- ADPoint;
- if (xVal.length <= period &&
- yValLen &&
- yVal[0].length !== 4) {
- return;
- }
- if (!volumeSeries) {
- error('Series ' +
- volumeSeriesID +
- ' not found! Check `volumeSeriesID`.', true, series.chart);
- return;
- }
- // i = period <-- skip first N-points
- // Calculate value one-by-one for each period in visible data
- for (i = period; i < yValLen; i++) {
- len = AD.length;
- ADPoint = populateAverage(xVal, yVal, yValVolume, i, period);
- if (len > 0) {
- ADPoint[1] += AD[len - 1][1];
- }
- AD.push(ADPoint);
- xData.push(ADPoint[0]);
- yData.push(ADPoint[1]);
- }
- return {
- values: AD,
- xData: xData,
- yData: yData
- };
- }
- });
- /**
- * A `AD` series. If the [type](#series.ad.type) option is not
- * specified, it is inherited from [chart.type](#chart.type).
- *
- * @extends series,plotOptions.ad
- * @since 6.0.0
- * @excluding dataParser, dataURL
- * @product highstock
- * @requires stock/indicators/indicators
- * @requires stock/indicators/accumulation-distribution
- * @apioption series.ad
- */
- ''; // add doclet above to transpiled file
- });
- _registerModule(_modules, 'Stock/Indicators/AOIndicator.js', [_modules['Core/Globals.js'], _modules['Core/Utilities.js']], function (H, U) {
- /* *
- *
- * License: www.highcharts.com/license
- *
- * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
- *
- * */
- var correctFloat = U.correctFloat,
- isArray = U.isArray,
- seriesType = U.seriesType;
- var noop = H.noop;
- /**
- * The AO series type
- *
- * @private
- * @class
- * @name Highcharts.seriesTypes.ao
- *
- * @augments Highcharts.Series
- */
- seriesType('ao', 'sma',
- /**
- * Awesome Oscillator. This series requires the `linkedTo` option to
- * be set and should be loaded after the `stock/indicators/indicators.js`
- *
- * @sample {highstock} stock/indicators/ao
- * Awesome
- *
- * @extends plotOptions.sma
- * @since 7.0.0
- * @product highstock
- * @excluding allAreas, colorAxis, joinBy, keys, navigatorOptions,
- * params, pointInterval, pointIntervalUnit, pointPlacement,
- * pointRange, pointStart, showInNavigator, stacking
- * @requires stock/indicators/indicators
- * @requires stock/indicators/ao
- * @optionparent plotOptions.ao
- */
- {
- /**
- * Color of the Awesome oscillator series bar that is greater than the
- * previous one. Note that if a `color` is defined, the `color`
- * takes precedence and the `greaterBarColor` is ignored.
- *
- * @sample {highstock} stock/indicators/ao/
- * greaterBarColor
- *
- * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
- * @since 7.0.0
- */
- greaterBarColor: '#06B535',
- /**
- * Color of the Awesome oscillator series bar that is lower than the
- * previous one. Note that if a `color` is defined, the `color`
- * takes precedence and the `lowerBarColor` is ignored.
- *
- * @sample {highstock} stock/indicators/ao/
- * lowerBarColor
- *
- * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
- * @since 7.0.0
- */
- lowerBarColor: '#F21313',
- threshold: 0,
- groupPadding: 0.2,
- pointPadding: 0.2,
- crisp: false,
- states: {
- hover: {
- halo: {
- size: 0
- }
- }
- }
- },
- /**
- * @lends Highcharts.Series#
- */
- {
- nameBase: 'AO',
- nameComponents: false,
- // Columns support:
- markerAttribs: noop,
- getColumnMetrics: H.seriesTypes.column.prototype.getColumnMetrics,
- crispCol: H.seriesTypes.column.prototype.crispCol,
- translate: H.seriesTypes.column.prototype.translate,
- drawPoints: H.seriesTypes.column.prototype.drawPoints,
- drawGraph: function () {
- var indicator = this,
- options = indicator.options,
- points = indicator.points,
- userColor = indicator.userOptions.color,
- positiveColor = options.greaterBarColor,
- negativeColor = options.lowerBarColor,
- firstPoint = points[0],
- i;
- if (!userColor && firstPoint) {
- firstPoint.color = positiveColor;
- for (i = 1; i < points.length; i++) {
- if (points[i].y > points[i - 1].y) {
- points[i].color = positiveColor;
- }
- else if (points[i].y < points[i - 1].y) {
- points[i].color = negativeColor;
- }
- else {
- points[i].color = points[i - 1].color;
- }
- }
- }
- },
- getValues: function (series) {
- var shortPeriod = 5,
- longPeriod = 34,
- xVal = series.xData || [],
- yVal = series.yData || [],
- yValLen = yVal.length,
- AO = [], // 0- date, 1- Awesome Oscillator
- xData = [],
- yData = [],
- high = 1,
- low = 2,
- shortSum = 0,
- longSum = 0,
- shortSMA, // Shorter Period SMA
- longSMA, // Longer Period SMA
- awesome,
- shortLastIndex,
- longLastIndex,
- price,
- i,
- j;
- if (xVal.length <= longPeriod ||
- !isArray(yVal[0]) ||
- yVal[0].length !== 4) {
- return;
- }
- for (i = 0; i < longPeriod - 1; i++) {
- price = (yVal[i][high] + yVal[i][low]) / 2;
- if (i >= longPeriod - shortPeriod) {
- shortSum = correctFloat(shortSum + price);
- }
- longSum = correctFloat(longSum + price);
- }
- for (j = longPeriod - 1; j < yValLen; j++) {
- price = (yVal[j][high] + yVal[j][low]) / 2;
- shortSum = correctFloat(shortSum + price);
- longSum = correctFloat(longSum + price);
- shortSMA = shortSum / shortPeriod;
- longSMA = longSum / longPeriod;
- awesome = correctFloat(shortSMA - longSMA);
- AO.push([xVal[j], awesome]);
- xData.push(xVal[j]);
- yData.push(awesome);
- shortLastIndex = j + 1 - shortPeriod;
- longLastIndex = j + 1 - longPeriod;
- shortSum = correctFloat(shortSum -
- (yVal[shortLastIndex][high] +
- yVal[shortLastIndex][low]) / 2);
- longSum = correctFloat(longSum -
- (yVal[longLastIndex][high] +
- yVal[longLastIndex][low]) / 2);
- }
- return {
- values: AO,
- xData: xData,
- yData: yData
- };
- }
- });
- /**
- * An `AO` series. If the [type](#series.ao.type)
- * option is not specified, it is inherited from [chart.type](#chart.type).
- *
- * @extends series,plotOptions.ao
- * @since 7.0.0
- * @product highstock
- * @excluding allAreas, colorAxis, dataParser, dataURL, joinBy, keys,
- * navigatorOptions, pointInterval, pointIntervalUnit,
- * pointPlacement, pointRange, pointStart, showInNavigator, stacking
- * @requires stock/indicators/indicators
- * @requires stock/indicators/ao
- * @apioption series.ao
- */
- ''; // for including the above in the doclets
- });
- _registerModule(_modules, 'Mixins/MultipleLines.js', [_modules['Core/Globals.js'], _modules['Core/Utilities.js']], function (H, U) {
- /**
- *
- * (c) 2010-2020 Wojciech Chmiel
- *
- * License: www.highcharts.com/license
- *
- * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
- *
- * */
- var defined = U.defined,
- error = U.error,
- merge = U.merge;
- var SMA = H.seriesTypes.sma;
- /**
- * Mixin useful for all indicators that have more than one line.
- * Merge it with your implementation where you will provide
- * getValues method appropriate to your indicator and pointArrayMap,
- * pointValKey, linesApiNames properites. Notice that pointArrayMap
- * should be consistent with amount of lines calculated in getValues method.
- *
- * @private
- * @mixin multipleLinesMixin
- */
- var multipleLinesMixin = {
- /* eslint-disable valid-jsdoc */
- /**
- * Lines ids. Required to plot appropriate amount of lines.
- * Notice that pointArrayMap should have more elements than
- * linesApiNames, because it contains main line and additional lines ids.
- * Also it should be consistent with amount of lines calculated in
- * getValues method from your implementation.
- *
- * @private
- * @name multipleLinesMixin.pointArrayMap
- * @type {Array<string>}
- */
- pointArrayMap: ['top', 'bottom'],
- /**
- * Main line id.
- *
- * @private
- * @name multipleLinesMixin.pointValKey
- * @type {string}
- */
- pointValKey: 'top',
- /**
- * Additional lines DOCS names. Elements of linesApiNames array should
- * be consistent with DOCS line names defined in your implementation.
- * Notice that linesApiNames should have decreased amount of elements
- * relative to pointArrayMap (without pointValKey).
- *
- * @private
- * @name multipleLinesMixin.linesApiNames
- * @type {Array<string>}
- */
- linesApiNames: ['bottomLine'],
- /**
- * Create translatedLines Collection based on pointArrayMap.
- *
- * @private
- * @function multipleLinesMixin.getTranslatedLinesNames
- * @param {string} [excludedValue]
- * Main line id
- * @return {Array<string>}
- * Returns translated lines names without excluded value.
- */
- getTranslatedLinesNames: function (excludedValue) {
- var translatedLines = [];
- (this.pointArrayMap || []).forEach(function (propertyName) {
- if (propertyName !== excludedValue) {
- translatedLines.push('plot' +
- propertyName.charAt(0).toUpperCase() +
- propertyName.slice(1));
- }
- });
- return translatedLines;
- },
- /**
- * @private
- * @function multipleLinesMixin.toYData
- * @param {Highcharts.Point} point
- * Indicator point
- * @return {Array<number>}
- * Returns point Y value for all lines
- */
- toYData: function (point) {
- var pointColl = [];
- (this.pointArrayMap || []).forEach(function (propertyName) {
- pointColl.push(point[propertyName]);
- });
- return pointColl;
- },
- /**
- * Add lines plot pixel values.
- *
- * @private
- * @function multipleLinesMixin.translate
- * @return {void}
- */
- translate: function () {
- var indicator = this,
- pointArrayMap = indicator.pointArrayMap,
- LinesNames = [],
- value;
- LinesNames = indicator.getTranslatedLinesNames();
- SMA.prototype.translate.apply(indicator, arguments);
- indicator.points.forEach(function (point) {
- pointArrayMap.forEach(function (propertyName, i) {
- value = point[propertyName];
- if (value !== null) {
- point[LinesNames[i]] = indicator.yAxis.toPixels(value, true);
- }
- });
- });
- },
- /**
- * Draw main and additional lines.
- *
- * @private
- * @function multipleLinesMixin.drawGraph
- * @return {void}
- */
- drawGraph: function () {
- var indicator = this,
- pointValKey = indicator.pointValKey,
- linesApiNames = indicator.linesApiNames,
- mainLinePoints = indicator.points,
- pointsLength = mainLinePoints.length,
- mainLineOptions = indicator.options,
- mainLinePath = indicator.graph,
- gappedExtend = {
- options: {
- gapSize: mainLineOptions.gapSize
- }
- },
- // additional lines point place holders:
- secondaryLines = [],
- secondaryLinesNames = indicator.getTranslatedLinesNames(pointValKey),
- point;
- // Generate points for additional lines:
- secondaryLinesNames.forEach(function (plotLine, index) {
- // create additional lines point place holders
- secondaryLines[index] = [];
- while (pointsLength--) {
- point = mainLinePoints[pointsLength];
- secondaryLines[index].push({
- x: point.x,
- plotX: point.plotX,
- plotY: point[plotLine],
- isNull: !defined(point[plotLine])
- });
- }
- pointsLength = mainLinePoints.length;
- });
- // Modify options and generate additional lines:
- linesApiNames.forEach(function (lineName, i) {
- if (secondaryLines[i]) {
- indicator.points = secondaryLines[i];
- if (mainLineOptions[lineName]) {
- indicator.options = merge(mainLineOptions[lineName].styles, gappedExtend);
- }
- else {
- error('Error: "There is no ' + lineName +
- ' in DOCS options declared. Check if linesApiNames' +
- ' are consistent with your DOCS line names."' +
- ' at mixin/multiple-line.js:34');
- }
- indicator.graph = indicator['graph' + lineName];
- SMA.prototype.drawGraph.call(indicator);
- // Now save lines:
- indicator['graph' + lineName] = indicator.graph;
- }
- else {
- error('Error: "' + lineName + ' doesn\'t have equivalent ' +
- 'in pointArrayMap. To many elements in linesApiNames ' +
- 'relative to pointArrayMap."');
- }
- });
- // Restore options and draw a main line:
- indicator.points = mainLinePoints;
- indicator.options = mainLineOptions;
- indicator.graph = mainLinePath;
- SMA.prototype.drawGraph.call(indicator);
- }
- };
- return multipleLinesMixin;
- });
- _registerModule(_modules, 'Stock/Indicators/AroonIndicator.js', [_modules['Core/Utilities.js'], _modules['Mixins/MultipleLines.js']], function (U, multipleLinesMixin) {
- /* *
- *
- * License: www.highcharts.com/license
- *
- * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
- *
- * */
- var merge = U.merge,
- pick = U.pick,
- seriesType = U.seriesType;
- /* eslint-disable valid-jsdoc */
- // Utils
- // Index of element with extreme value from array (min or max)
- /**
- * @private
- */
- function getExtremeIndexInArray(arr, extreme) {
- var extremeValue = arr[0],
- valueIndex = 0,
- i;
- for (i = 1; i < arr.length; i++) {
- if (extreme === 'max' && arr[i] >= extremeValue ||
- extreme === 'min' && arr[i] <= extremeValue) {
- extremeValue = arr[i];
- valueIndex = i;
- }
- }
- return valueIndex;
- }
- /* eslint-enable valid-jsdoc */
- /**
- * The Aroon series type.
- *
- * @private
- * @class
- * @name Highcharts.seriesTypes.aroon
- *
- * @augments Highcharts.Series
- */
- seriesType('aroon', 'sma',
- /**
- * Aroon. This series requires the `linkedTo` option to be
- * set and should be loaded after the `stock/indicators/indicators.js`.
- *
- * @sample {highstock} stock/indicators/aroon
- * Aroon
- *
- * @extends plotOptions.sma
- * @since 7.0.0
- * @product highstock
- * @excluding allAreas, colorAxis, compare, compareBase, joinBy, keys,
- * navigatorOptions, pointInterval, pointIntervalUnit,
- * pointPlacement, pointRange, pointStart, showInNavigator,
- * stacking
- * @requires stock/indicators/indicators
- * @requires stock/indicators/aroon
- * @optionparent plotOptions.aroon
- */
- {
- /**
- * Paramters used in calculation of aroon series points.
- *
- * @excluding periods, index
- */
- params: {
- /**
- * Period for Aroon indicator
- */
- period: 25
- },
- marker: {
- enabled: false
- },
- tooltip: {
- pointFormat: '<span style="color:{point.color}">\u25CF</span><b> {series.name}</b><br/>Aroon Up: {point.y}<br/>Aroon Down: {point.aroonDown}<br/>'
- },
- /**
- * aroonDown line options.
- */
- aroonDown: {
- /**
- * Styles for an aroonDown line.
- */
- styles: {
- /**
- * Pixel width of the line.
- */
- lineWidth: 1,
- /**
- * Color of the line. If not set, it's inherited from
- * [plotOptions.aroon.color](#plotOptions.aroon.color).
- *
- * @type {Highcharts.ColorString}
- */
- lineColor: void 0
- }
- },
- dataGrouping: {
- approximation: 'averages'
- }
- },
- /**
- * @lends Highcharts.Series#
- */
- merge(multipleLinesMixin, {
- nameBase: 'Aroon',
- pointArrayMap: ['y', 'aroonDown'],
- pointValKey: 'y',
- linesApiNames: ['aroonDown'],
- getValues: function (series, params) {
- var period = params.period,
- xVal = series.xData,
- yVal = series.yData,
- yValLen = yVal ? yVal.length : 0,
- // 0- date, 1- Aroon Up, 2- Aroon Down
- AR = [],
- xData = [],
- yData = [],
- slicedY,
- low = 2,
- high = 1,
- aroonUp,
- aroonDown,
- xLow,
- xHigh,
- i;
- // For a N-period, we start from N-1 point, to calculate Nth point
- // That is why we later need to comprehend slice() elements list
- // with (+1)
- for (i = period - 1; i < yValLen; i++) {
- slicedY = yVal.slice(i - period + 1, i + 2);
- xLow = getExtremeIndexInArray(slicedY.map(function (elem) {
- return pick(elem[low], elem);
- }), 'min');
- xHigh = getExtremeIndexInArray(slicedY.map(function (elem) {
- return pick(elem[high], elem);
- }), 'max');
- aroonUp = (xHigh / period) * 100;
- aroonDown = (xLow / period) * 100;
- if (xVal[i + 1]) {
- AR.push([xVal[i + 1], aroonUp, aroonDown]);
- xData.push(xVal[i + 1]);
- yData.push([aroonUp, aroonDown]);
- }
- }
- return {
- values: AR,
- xData: xData,
- yData: yData
- };
- }
- }));
- /**
- * A Aroon indicator. If the [type](#series.aroon.type) option is not
- * specified, it is inherited from [chart.type](#chart.type).
- *
- * @extends series,plotOptions.aroon
- * @since 7.0.0
- * @product highstock
- * @excluding allAreas, colorAxis, compare, compareBase, dataParser, dataURL,
- * joinBy, keys, navigatorOptions, pointInterval, pointIntervalUnit,
- * pointPlacement, pointRange, pointStart, showInNavigator, stacking
- * @requires stock/indicators/indicators
- * @requires stock/indicators/aroon
- * @apioption series.aroon
- */
- ''; // to avoid removal of the above jsdoc
- });
- _registerModule(_modules, 'Stock/Indicators/AroonOscillatorIndicator.js', [_modules['Core/Globals.js'], _modules['Mixins/MultipleLines.js'], _modules['Mixins/IndicatorRequired.js'], _modules['Core/Utilities.js']], function (H, multipleLinesMixin, requiredIndicator, U) {
- /* *
- *
- * License: www.highcharts.com/license
- *
- * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
- *
- * */
- var merge = U.merge,
- seriesType = U.seriesType;
- var AROON = H.seriesTypes.aroon;
- /**
- * The Aroon Oscillator series type.
- *
- * @private
- * @class
- * @name Highcharts.seriesTypes.aroonoscillator
- *
- * @augments Highcharts.Series
- */
- seriesType('aroonoscillator', 'aroon',
- /**
- * Aroon Oscillator. This series requires the `linkedTo` option to be set
- * and should be loaded after the `stock/indicators/indicators.js` and
- * `stock/indicators/aroon.js`.
- *
- * @sample {highstock} stock/indicators/aroon-oscillator
- * Aroon Oscillator
- *
- * @extends plotOptions.aroon
- * @since 7.0.0
- * @product highstock
- * @excluding allAreas, aroonDown, colorAxis, compare, compareBase,
- * joinBy, keys, navigatorOptions, pointInterval,
- * pointIntervalUnit, pointPlacement, pointRange, pointStart,
- * showInNavigator, stacking
- * @requires stock/indicators/indicators
- * @requires stock/indicators/aroon
- * @requires stock/indicators/aroon-oscillator
- * @optionparent plotOptions.aroonoscillator
- */
- {
- /**
- * Paramters used in calculation of aroon oscillator series points.
- *
- * @excluding periods, index
- */
- params: {
- /**
- * Period for Aroon Oscillator
- *
- * @since 7.0.0
- * @product highstock
- */
- period: 25
- },
- tooltip: {
- pointFormat: '<span style="color:{point.color}">\u25CF</span><b> {series.name}</b>: {point.y}'
- }
- },
- /**
- * @lends Highcharts.Series#
- */
- merge(multipleLinesMixin, {
- nameBase: 'Aroon Oscillator',
- pointArrayMap: ['y'],
- pointValKey: 'y',
- linesApiNames: [],
- init: function () {
- var args = arguments,
- ctx = this;
- requiredIndicator.isParentLoaded(AROON, 'aroon', ctx.type, function (indicator) {
- indicator.prototype.init.apply(ctx, args);
- return;
- });
- },
- getValues: function (series, params) {
- // 0- date, 1- Aroon Oscillator
- var ARO = [],
- xData = [],
- yData = [],
- aroon,
- aroonUp,
- aroonDown,
- oscillator,
- i;
- aroon = AROON.prototype.getValues.call(this, series, params);
- for (i = 0; i < aroon.yData.length; i++) {
- aroonUp = aroon.yData[i][0];
- aroonDown = aroon.yData[i][1];
- oscillator = aroonUp - aroonDown;
- ARO.push([aroon.xData[i], oscillator]);
- xData.push(aroon.xData[i]);
- yData.push(oscillator);
- }
- return {
- values: ARO,
- xData: xData,
- yData: yData
- };
- }
- }));
- /**
- * An `Aroon Oscillator` series. If the [type](#series.aroonoscillator.type)
- * option is not specified, it is inherited from [chart.type](#chart.type).
- *
- * @extends series,plotOptions.aroonoscillator
- * @since 7.0.0
- * @product highstock
- * @excluding allAreas, aroonDown, colorAxis, compare, compareBase, dataParser,
- * dataURL, joinBy, keys, navigatorOptions, pointInterval,
- * pointIntervalUnit, pointPlacement, pointRange, pointStart,
- * showInNavigator, stacking
- * @requires stock/indicators/indicators
- * @requires stock/indicators/aroon
- * @requires stock/indicators/aroon-oscillator
- * @apioption series.aroonoscillator
- */
- ''; // adds doclet above to the transpiled file
- });
- _registerModule(_modules, 'Stock/Indicators/ATRIndicator.js', [_modules['Core/Utilities.js']], function (U) {
- /* *
- *
- * License: www.highcharts.com/license
- *
- * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
- *
- * */
- var isArray = U.isArray,
- seriesType = U.seriesType;
- var UNDEFINED;
- /* eslint-disable valid-jsdoc */
- // Utils:
- /**
- * @private
- */
- function accumulateAverage(points, xVal, yVal, i) {
- var xValue = xVal[i],
- yValue = yVal[i];
- points.push([xValue, yValue]);
- }
- /**
- * @private
- */
- function getTR(currentPoint, prevPoint) {
- var pointY = currentPoint,
- prevY = prevPoint,
- HL = pointY[1] - pointY[2],
- HCp = prevY === UNDEFINED ? 0 : Math.abs(pointY[1] - prevY[3]),
- LCp = prevY === UNDEFINED ? 0 : Math.abs(pointY[2] - prevY[3]),
- TR = Math.max(HL,
- HCp,
- LCp);
- return TR;
- }
- /**
- * @private
- */
- function populateAverage(points, xVal, yVal, i, period, prevATR) {
- var x = xVal[i - 1],
- TR = getTR(yVal[i - 1],
- yVal[i - 2]),
- y;
- y = (((prevATR * (period - 1)) + TR) / period);
- return [x, y];
- }
- /* eslint-enable valid-jsdoc */
- /**
- * The ATR series type.
- *
- * @private
- * @class
- * @name Highcharts.seriesTypes.atr
- *
- * @augments Highcharts.Series
- */
- seriesType('atr', 'sma',
- /**
- * Average true range indicator (ATR). This series requires `linkedTo`
- * option to be set.
- *
- * @sample stock/indicators/atr
- * ATR indicator
- *
- * @extends plotOptions.sma
- * @since 6.0.0
- * @product highstock
- * @requires stock/indicators/indicators
- * @requires stock/indicators/atr
- * @optionparent plotOptions.atr
- */
- {
- params: {
- period: 14
- }
- },
- /**
- * @lends Highcharts.Series#
- */
- {
- getValues: function (series, params) {
- var period = params.period,
- xVal = series.xData,
- yVal = series.yData,
- yValLen = yVal ? yVal.length : 0,
- xValue = xVal[0],
- yValue = yVal[0],
- range = 1,
- prevATR = 0,
- TR = 0,
- ATR = [],
- xData = [],
- yData = [],
- point,
- i,
- points;
- points = [[xValue, yValue]];
- if ((xVal.length <= period) ||
- !isArray(yVal[0]) ||
- yVal[0].length !== 4) {
- return;
- }
- for (i = 1; i <= yValLen; i++) {
- accumulateAverage(points, xVal, yVal, i);
- if (period < range) {
- point = populateAverage(points, xVal, yVal, i, period, prevATR);
- prevATR = point[1];
- ATR.push(point);
- xData.push(point[0]);
- yData.push(point[1]);
- }
- else if (period === range) {
- prevATR = TR / (i - 1);
- ATR.push([xVal[i - 1], prevATR]);
- xData.push(xVal[i - 1]);
- yData.push(prevATR);
- range++;
- }
- else {
- TR += getTR(yVal[i - 1], yVal[i - 2]);
- range++;
- }
- }
- return {
- values: ATR,
- xData: xData,
- yData: yData
- };
- }
- });
- /**
- * A `ATR` series. If the [type](#series.atr.type) option is not specified, it
- * is inherited from [chart.type](#chart.type).
- *
- * @extends series,plotOptions.atr
- * @since 6.0.0
- * @product highstock
- * @excluding dataParser, dataURL
- * @requires stock/indicators/indicators
- * @requires stock/indicators/atr
- * @apioption series.atr
- */
- ''; // to include the above in the js output
- });
- _registerModule(_modules, 'Stock/Indicators/BBIndicator.js', [_modules['Core/Globals.js'], _modules['Core/Utilities.js'], _modules['Mixins/MultipleLines.js']], function (H, U, multipleLinesMixin) {
- /**
- *
- * License: www.highcharts.com/license
- *
- * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
- *
- * */
- var isArray = U.isArray,
- merge = U.merge,
- seriesType = U.seriesType;
- var SMA = H.seriesTypes.sma;
- /* eslint-disable valid-jsdoc */
- // Utils:
- /**
- * @private
- */
- function getStandardDeviation(arr, index, isOHLC, mean) {
- var variance = 0,
- arrLen = arr.length,
- std = 0,
- i = 0,
- value;
- for (; i < arrLen; i++) {
- value = (isOHLC ? arr[i][index] : arr[i]) - mean;
- variance += value * value;
- }
- variance = variance / (arrLen - 1);
- std = Math.sqrt(variance);
- return std;
- }
- /* eslint-enable valid-jsdoc */
- /**
- * Bollinger Bands series type.
- *
- * @private
- * @class
- * @name Highcharts.seriesTypes.bb
- *
- * @augments Highcharts.Series
- */
- seriesType('bb', 'sma',
- /**
- * Bollinger bands (BB). This series requires the `linkedTo` option to be
- * set and should be loaded after the `stock/indicators/indicators.js` file.
- *
- * @sample stock/indicators/bollinger-bands
- * Bollinger bands
- *
- * @extends plotOptions.sma
- * @since 6.0.0
- * @product highstock
- * @requires stock/indicators/indicators
- * @requires stock/indicators/bollinger-bands
- * @optionparent plotOptions.bb
- */
- {
- params: {
- period: 20,
- /**
- * Standard deviation for top and bottom bands.
- */
- standardDeviation: 2,
- index: 3
- },
- /**
- * Bottom line options.
- */
- bottomLine: {
- /**
- * Styles for a bottom line.
- */
- styles: {
- /**
- * Pixel width of the line.
- */
- lineWidth: 1,
- /**
- * Color of the line. If not set, it's inherited from
- * [plotOptions.bb.color](#plotOptions.bb.color).
- *
- * @type {Highcharts.ColorString}
- */
- lineColor: void 0
- }
- },
- /**
- * Top line options.
- *
- * @extends plotOptions.bb.bottomLine
- */
- topLine: {
- styles: {
- lineWidth: 1,
- /**
- * @type {Highcharts.ColorString}
- */
- lineColor: void 0
- }
- },
- tooltip: {
- pointFormat: '<span style="color:{point.color}">\u25CF</span><b> {series.name}</b><br/>Top: {point.top}<br/>Middle: {point.middle}<br/>Bottom: {point.bottom}<br/>'
- },
- marker: {
- enabled: false
- },
- dataGrouping: {
- approximation: 'averages'
- }
- },
- /**
- * @lends Highcharts.Series#
- */
- merge(multipleLinesMixin, {
- pointArrayMap: ['top', 'middle', 'bottom'],
- pointValKey: 'middle',
- nameComponents: ['period', 'standardDeviation'],
- linesApiNames: ['topLine', 'bottomLine'],
- init: function () {
- SMA.prototype.init.apply(this, arguments);
- // Set default color for lines:
- this.options = merge({
- topLine: {
- styles: {
- lineColor: this.color
- }
- },
- bottomLine: {
- styles: {
- lineColor: this.color
- }
- }
- }, this.options);
- },
- getValues: function (series, params) {
- var period = params.period,
- standardDeviation = params.standardDeviation,
- xVal = series.xData,
- yVal = series.yData,
- yValLen = yVal ? yVal.length : 0,
- // 0- date, 1-middle line, 2-top line, 3-bottom line
- BB = [],
- // middle line, top line and bottom line
- ML,
- TL,
- BL,
- date,
- xData = [],
- yData = [],
- slicedX,
- slicedY,
- stdDev,
- isOHLC,
- point,
- i;
- if (xVal.length < period) {
- return;
- }
- isOHLC = isArray(yVal[0]);
- for (i = period; i <= yValLen; i++) {
- slicedX = xVal.slice(i - period, i);
- slicedY = yVal.slice(i - period, i);
- point = SMA.prototype.getValues.call(this, {
- xData: slicedX,
- yData: slicedY
- }, params);
- date = point.xData[0];
- ML = point.yData[0];
- stdDev = getStandardDeviation(slicedY, params.index, isOHLC, ML);
- TL = ML + standardDeviation * stdDev;
- BL = ML - standardDeviation * stdDev;
- BB.push([date, TL, ML, BL]);
- xData.push(date);
- yData.push([TL, ML, BL]);
- }
- return {
- values: BB,
- xData: xData,
- yData: yData
- };
- }
- }));
- /**
- * A bollinger bands indicator. If the [type](#series.bb.type) option is not
- * specified, it is inherited from [chart.type](#chart.type).
- *
- * @extends series,plotOptions.bb
- * @since 6.0.0
- * @excluding dataParser, dataURL
- * @product highstock
- * @requires stock/indicators/indicators
- * @requires stock/indicators/bollinger-bands
- * @apioption series.bb
- */
- ''; // to include the above in the js output
- });
- _registerModule(_modules, 'Stock/Indicators/CCIIndicator.js', [_modules['Core/Utilities.js']], function (U) {
- /* *
- *
- * License: www.highcharts.com/license
- *
- * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
- * */
- var isArray = U.isArray,
- seriesType = U.seriesType;
- /* eslint-disable valid-jsdoc */
- // Utils:
- /**
- * @private
- */
- function sumArray(array) {
- return array.reduce(function (prev, cur) {
- return prev + cur;
- }, 0);
- }
- /**
- * @private
- */
- function meanDeviation(arr, sma) {
- var len = arr.length,
- sum = 0,
- i;
- for (i = 0; i < len; i++) {
- sum += Math.abs(sma - (arr[i]));
- }
- return sum;
- }
- /* eslint-enable valid-jsdoc */
- /**
- * The CCI series type.
- *
- * @private
- * @class
- * @name Highcharts.seriesTypes.cci
- *
- * @augments Highcharts.Series
- */
- seriesType('cci', 'sma',
- /**
- * Commodity Channel Index (CCI). This series requires `linkedTo` option to
- * be set.
- *
- * @sample stock/indicators/cci
- * CCI indicator
- *
- * @extends plotOptions.sma
- * @since 6.0.0
- * @product highstock
- * @requires stock/indicators/indicators
- * @requires stock/indicators/cci
- * @optionparent plotOptions.cci
- */
- {
- params: {
- period: 14
- }
- },
- /**
- * @lends Highcharts.Series#
- */
- {
- getValues: function (series, params) {
- var period = params.period,
- xVal = series.xData,
- yVal = series.yData,
- yValLen = yVal ? yVal.length : 0,
- TP = [],
- periodTP = [],
- range = 1,
- CCI = [],
- xData = [],
- yData = [],
- CCIPoint,
- p,
- len,
- smaTP,
- TPtemp,
- meanDev,
- i;
- // CCI requires close value
- if (xVal.length <= period ||
- !isArray(yVal[0]) ||
- yVal[0].length !== 4) {
- return;
- }
- // accumulate first N-points
- while (range < period) {
- p = yVal[range - 1];
- TP.push((p[1] + p[2] + p[3]) / 3);
- range++;
- }
- for (i = period; i <= yValLen; i++) {
- p = yVal[i - 1];
- TPtemp = (p[1] + p[2] + p[3]) / 3;
- len = TP.push(TPtemp);
- periodTP = TP.slice(len - period);
- smaTP = sumArray(periodTP) / period;
- meanDev = meanDeviation(periodTP, smaTP) / period;
- CCIPoint = ((TPtemp - smaTP) / (0.015 * meanDev));
- CCI.push([xVal[i - 1], CCIPoint]);
- xData.push(xVal[i - 1]);
- yData.push(CCIPoint);
- }
- return {
- values: CCI,
- xData: xData,
- yData: yData
- };
- }
- });
- /**
- * A `CCI` series. If the [type](#series.cci.type) option is not
- * specified, it is inherited from [chart.type](#chart.type).
- *
- * @extends series,plotOptions.cci
- * @since 6.0.0
- * @excluding dataParser, dataURL
- * @product highstock
- * @requires stock/indicators/indicators
- * @requires stock/indicators/cci
- * @apioption series.cci
- */
- ''; // to include the above in the js output
- });
- _registerModule(_modules, 'Stock/Indicators/CMFIndicator.js', [_modules['Core/Utilities.js']], function (U) {
- /* *
- *
- * (c) 2010-2020 Highsoft AS
- *
- * Author: Sebastian Domas
- *
- * Chaikin Money Flow indicator for Highstock
- *
- * License: www.highcharts.com/license
- *
- * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
- *
- * */
- var seriesType = U.seriesType;
- /**
- * The CMF series type.
- *
- * @private
- * @class
- * @name Highcharts.seriesTypes.cmf
- *
- * @augments Highcharts.Series
- */
- seriesType('cmf', 'sma',
- /**
- * Chaikin Money Flow indicator (cmf).
- *
- * @sample stock/indicators/cmf/
- * Chaikin Money Flow indicator
- *
- * @extends plotOptions.sma
- * @since 6.0.0
- * @excluding animationLimit
- * @product highstock
- * @requires stock/indicators/indicators
- * @requires stock/indicators/cmf
- * @optionparent plotOptions.cmf
- */
- {
- params: {
- period: 14,
- /**
- * The id of another series to use its data as volume data for the
- * indiator calculation.
- */
- volumeSeriesID: 'volume'
- }
- },
- /**
- * @lends Highcharts.Series#
- */
- {
- nameBase: 'Chaikin Money Flow',
- /**
- * Checks if the series and volumeSeries are accessible, number of
- * points.x is longer than period, is series has OHLC data
- * @private
- * @param {Highcharts.CMFIndicator} this indicator to use.
- * @return {boolean} True if series is valid and can be computed,
- * otherwise false.
- */
- isValid: function () {
- var chart = this.chart,
- options = this.options,
- series = this.linkedParent,
- volumeSeries = (this.volumeSeries ||
- (this.volumeSeries =
- chart.get(options.params.volumeSeriesID))),
- isSeriesOHLC = (series &&
- series.yData &&
- series.yData[0].length === 4);
- /**
- * @private
- * @param {Highcharts.Series} serie to check length validity on.
- * @return {boolean|undefined} true if length is valid.
- */
- function isLengthValid(serie) {
- return serie.xData &&
- serie.xData.length >= options.params.period;
- }
- return !!(series &&
- volumeSeries &&
- isLengthValid(series) &&
- isLengthValid(volumeSeries) && isSeriesOHLC);
- },
- /**
- * Returns indicator's data.
- * @private
- * @param {Highcharts.CMFIndicator} this indicator to use.
- * @param {Highcharts.Series} series to calculate values from
- * @param {Highcharts.CMFIndicatorParamsOptions} params to pass
- * @return {boolean|Highcharts.IndicatorNullableValuesObject} Returns false if the
- * indicator is not valid, otherwise returns Values object.
- */
- getValues: function (series, params) {
- if (!this.isValid()) {
- return;
- }
- return this.getMoneyFlow(series.xData, series.yData, this.volumeSeries.yData, params.period);
- },
- /**
- * @private
- * @param {Array<number>} xData - x timestamp values
- * @param {Array<number>} seriesYData - yData of basic series
- * @param {Array<number>} volumeSeriesYData - yData of volume series
- * @param {number} period - indicator's param
- * @return {Highcharts.IndicatorNullableValuesObject} object containing computed money
- * flow data
- */
- getMoneyFlow: function (xData, seriesYData, volumeSeriesYData, period) {
- var len = seriesYData.length,
- moneyFlowVolume = [],
- sumVolume = 0,
- sumMoneyFlowVolume = 0,
- moneyFlowXData = [],
- moneyFlowYData = [],
- values = [],
- i,
- point,
- nullIndex = -1;
- /**
- * Calculates money flow volume, changes i, nullIndex vars from
- * upper scope!
- * @private
- * @param {Array<number>} ohlc - OHLC point
- * @param {number} volume - Volume point's y value
- * @return {number|null} - volume * moneyFlowMultiplier
- **/
- function getMoneyFlowVolume(ohlc, volume) {
- var high = ohlc[1],
- low = ohlc[2],
- close = ohlc[3],
- isValid = volume !== null &&
- high !== null &&
- low !== null &&
- close !== null &&
- high !== low;
- /**
- * @private
- * @param {number} h - High value
- * @param {number} l - Low value
- * @param {number} c - Close value
- * @return {number} calculated multiplier for the point
- **/
- function getMoneyFlowMultiplier(h, l, c) {
- return ((c - l) - (h - c)) / (h - l);
- }
- return isValid ?
- getMoneyFlowMultiplier(high, low, close) * volume :
- ((nullIndex = i), null);
- }
- if (period > 0 && period <= len) {
- for (i = 0; i < period; i++) {
- moneyFlowVolume[i] = getMoneyFlowVolume(seriesYData[i], volumeSeriesYData[i]);
- sumVolume += volumeSeriesYData[i];
- sumMoneyFlowVolume += moneyFlowVolume[i];
- }
- moneyFlowXData.push(xData[i - 1]);
- moneyFlowYData.push(i - nullIndex >= period && sumVolume !== 0 ?
- sumMoneyFlowVolume / sumVolume :
- null);
- values.push([moneyFlowXData[0], moneyFlowYData[0]]);
- for (; i < len; i++) {
- moneyFlowVolume[i] = getMoneyFlowVolume(seriesYData[i], volumeSeriesYData[i]);
- sumVolume -= volumeSeriesYData[i - period];
- sumVolume += volumeSeriesYData[i];
- sumMoneyFlowVolume -= moneyFlowVolume[i - period];
- sumMoneyFlowVolume += moneyFlowVolume[i];
- point = [
- xData[i],
- i - nullIndex >= period ?
- sumMoneyFlowVolume / sumVolume :
- null
- ];
- moneyFlowXData.push(point[0]);
- moneyFlowYData.push(point[1]);
- values.push([point[0], point[1]]);
- }
- }
- return {
- values: values,
- xData: moneyFlowXData,
- yData: moneyFlowYData
- };
- }
- });
- /**
- * A `CMF` series. If the [type](#series.cmf.type) option is not
- * specified, it is inherited from [chart.type](#chart.type).
- *
- * @extends series,plotOptions.cmf
- * @since 6.0.0
- * @product highstock
- * @excluding dataParser, dataURL
- * @requires stock/indicators/indicators
- * @requires stock/indicators/cmf
- * @apioption series.cmf
- */
- ''; // adds doclet above to the transpiled file
- });
- _registerModule(_modules, 'Stock/Indicators/DPOIndicator.js', [_modules['Core/Utilities.js']], function (U) {
- /* *
- *
- * License: www.highcharts.com/license
- *
- * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
- *
- * */
- var correctFloat = U.correctFloat,
- pick = U.pick,
- seriesType = U.seriesType;
- /* eslint-disable valid-jsdoc */
- // Utils
- /**
- * @private
- */
- function accumulatePoints(sum, yVal, i, index, subtract) {
- var price = pick(yVal[i][index],
- yVal[i]);
- if (subtract) {
- return correctFloat(sum - price);
- }
- return correctFloat(sum + price);
- }
- /* eslint-enable valid-jsdoc */
- /**
- * The DPO series type.
- *
- * @private
- * @class
- * @name Highcharts.seriesTypes.dpo
- *
- * @augments Highcharts.Series
- */
- seriesType('dpo', 'sma',
- /**
- * Detrended Price Oscillator. This series requires the `linkedTo` option to
- * be set and should be loaded after the `stock/indicators/indicators.js`.
- *
- * @sample {highstock} stock/indicators/dpo
- * Detrended Price Oscillator
- *
- * @extends plotOptions.sma
- * @since 7.0.0
- * @product highstock
- * @excluding allAreas, colorAxis, compare, compareBase, joinBy, keys,
- * navigatorOptions, pointInterval, pointIntervalUnit,
- * pointPlacement, pointRange, pointStart, showInNavigator,
- * stacking
- * @requires stock/indicators/indicators
- * @requires stock/indicators/dpo
- * @optionparent plotOptions.dpo
- */
- {
- /**
- * Parameters used in calculation of Detrended Price Oscillator series
- * points.
- */
- params: {
- /**
- * Period for Detrended Price Oscillator
- */
- period: 21
- }
- },
- /**
- * @lends Highcharts.Series#
- */
- {
- nameBase: 'DPO',
- getValues: function (series, params) {
- var period = params.period,
- index = params.index,
- offset = Math.floor(period / 2 + 1),
- range = period + offset,
- xVal = series.xData || [],
- yVal = series.yData || [],
- yValLen = yVal.length,
- // 0- date, 1- Detrended Price Oscillator
- DPO = [],
- xData = [],
- yData = [],
- sum = 0,
- oscillator,
- periodIndex,
- rangeIndex,
- price,
- i,
- j;
- if (xVal.length <= range) {
- return;
- }
- // Accumulate first N-points for SMA
- for (i = 0; i < period - 1; i++) {
- sum = accumulatePoints(sum, yVal, i, index);
- }
- // Detrended Price Oscillator formula:
- // DPO = Price - Simple moving average [from (n / 2 + 1) days ago]
- for (j = 0; j <= yValLen - range; j++) {
- periodIndex = j + period - 1;
- rangeIndex = j + range - 1;
- // adding the last period point
- sum = accumulatePoints(sum, yVal, periodIndex, index);
- price = pick(yVal[rangeIndex][index], yVal[rangeIndex]);
- oscillator = price - sum / period;
- // substracting the first period point
- sum = accumulatePoints(sum, yVal, j, index, true);
- DPO.push([xVal[rangeIndex], oscillator]);
- xData.push(xVal[rangeIndex]);
- yData.push(oscillator);
- }
- return {
- values: DPO,
- xData: xData,
- yData: yData
- };
- }
- });
- /**
- * A Detrended Price Oscillator. If the [type](#series.dpo.type) option is not
- * specified, it is inherited from [chart.type](#chart.type).
- *
- * @extends series,plotOptions.dpo
- * @since 7.0.0
- * @product highstock
- * @excluding allAreas, colorAxis, compare, compareBase, dataParser, dataURL,
- * joinBy, keys, navigatorOptions, pointInterval, pointIntervalUnit,
- * pointPlacement, pointRange, pointStart, showInNavigator, stacking
- * @requires stock/indicators/indicators
- * @requires stock/indicators/dpo
- * @apioption series.dpo
- */
- ''; // to include the above in the js output'
- });
- _registerModule(_modules, 'Stock/Indicators/EMAIndicator.js', [_modules['Core/Utilities.js']], function (U) {
- /* *
- *
- * License: www.highcharts.com/license
- *
- * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
- *
- * */
- var correctFloat = U.correctFloat,
- isArray = U.isArray,
- seriesType = U.seriesType;
- /**
- * The EMA series type.
- *
- * @private
- * @class
- * @name Highcharts.seriesTypes.ema
- *
- * @augments Highcharts.Series
- */
- seriesType('ema', 'sma',
- /**
- * Exponential moving average indicator (EMA). This series requires the
- * `linkedTo` option to be set.
- *
- * @sample stock/indicators/ema
- * Exponential moving average indicator
- *
- * @extends plotOptions.sma
- * @since 6.0.0
- * @product highstock
- * @requires stock/indicators/indicators
- * @requires stock/indicators/ema
- * @optionparent plotOptions.ema
- */
- {
- params: {
- /**
- * The point index which indicator calculations will base. For
- * example using OHLC data, index=2 means the indicator will be
- * calculated using Low values.
- *
- * By default index value used to be set to 0. Since Highstock 7
- * by default index is set to 3 which means that the ema
- * indicator will be calculated using Close values.
- */
- index: 3,
- period: 9 // @merge 14 in v6.2
- }
- },
- /**
- * @lends Highcharts.Series#
- */
- {
- accumulatePeriodPoints: function (period, index, yVal) {
- var sum = 0,
- i = 0,
- y = 0;
- while (i < period) {
- y = index < 0 ? yVal[i] : yVal[i][index];
- sum = sum + y;
- i++;
- }
- return sum;
- },
- calculateEma: function (xVal, yVal, i, EMApercent, calEMA, index, SMA) {
- var x = xVal[i - 1],
- yValue = index < 0 ?
- yVal[i - 1] :
- yVal[i - 1][index],
- y;
- y = typeof calEMA === 'undefined' ?
- SMA : correctFloat((yValue * EMApercent) +
- (calEMA * (1 - EMApercent)));
- return [x, y];
- },
- getValues: function (series, params) {
- var period = params.period,
- xVal = series.xData,
- yVal = series.yData,
- yValLen = yVal ? yVal.length : 0,
- EMApercent = 2 / (period + 1),
- sum = 0,
- EMA = [],
- xData = [],
- yData = [],
- index = -1,
- SMA = 0,
- calEMA,
- EMAPoint,
- i;
- // Check period, if bigger than points length, skip
- if (yValLen < period) {
- return;
- }
- // Switch index for OHLC / Candlestick / Arearange
- if (isArray(yVal[0])) {
- index = params.index ? params.index : 0;
- }
- // Accumulate first N-points
- sum = this.accumulatePeriodPoints(period, index, yVal);
- // first point
- SMA = sum / period;
- // Calculate value one-by-one for each period in visible data
- for (i = period; i < yValLen + 1; i++) {
- EMAPoint = this.calculateEma(xVal, yVal, i, EMApercent, calEMA, index, SMA);
- EMA.push(EMAPoint);
- xData.push(EMAPoint[0]);
- yData.push(EMAPoint[1]);
- calEMA = EMAPoint[1];
- }
- return {
- values: EMA,
- xData: xData,
- yData: yData
- };
- }
- });
- /**
- * A `EMA` series. If the [type](#series.ema.type) option is not
- * specified, it is inherited from [chart.type](#chart.type).
- *
- * @extends series,plotOptions.ema
- * @since 6.0.0
- * @product highstock
- * @excluding dataParser, dataURL
- * @requires stock/indicators/indicators
- * @requires stock/indicators/ema
- * @apioption series.ema
- */
- ''; // adds doclet above to the transpiled file
- });
- _registerModule(_modules, 'Stock/Indicators/ChaikinIndicator.js', [_modules['Core/Globals.js'], _modules['Core/Utilities.js'], _modules['Mixins/IndicatorRequired.js']], function (H, U, requiredIndicator) {
- /* *
- *
- * License: www.highcharts.com/license
- *
- * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
- *
- * */
- var correctFloat = U.correctFloat,
- error = U.error,
- seriesType = U.seriesType;
- var EMA = H.seriesTypes.ema,
- AD = H.seriesTypes.ad;
- /**
- * The Chaikin series type.
- *
- * @private
- * @class
- * @name Highcharts.seriesTypes.chaikin
- *
- * @augments Highcharts.Series
- */
- seriesType('chaikin', 'ema',
- /**
- * Chaikin Oscillator. This series requires the `linkedTo` option to
- * be set and should be loaded after the `stock/indicators/indicators.js`
- * and `stock/indicators/ema.js`.
- *
- * @sample {highstock} stock/indicators/chaikin
- * Chaikin Oscillator
- *
- * @extends plotOptions.ema
- * @since 7.0.0
- * @product highstock
- * @excluding allAreas, colorAxis, joinBy, keys, navigatorOptions,
- * pointInterval, pointIntervalUnit, pointPlacement,
- * pointRange, pointStart, showInNavigator, stacking
- * @requires stock/indicators/indicators
- * @requires stock/indicators/ema
- * @requires stock/indicators/chaikin
- * @optionparent plotOptions.chaikin
- */
- {
- /**
- * Paramters used in calculation of Chaikin Oscillator
- * series points.
- *
- * @excluding index, period
- */
- params: {
- /**
- * The id of volume series which is mandatory.
- * For example using OHLC data, volumeSeriesID='volume' means
- * the indicator will be calculated using OHLC and volume values.
- */
- volumeSeriesID: 'volume',
- /**
- * Periods for Chaikin Oscillator calculations.
- *
- * @type {Array<number>}
- * @default [3, 10]
- */
- periods: [3, 10]
- }
- },
- /**
- * @lends Highcharts.Series#
- */
- {
- nameBase: 'Chaikin Osc',
- nameComponents: ['periods'],
- init: function () {
- var args = arguments,
- ctx = this;
- requiredIndicator.isParentLoaded(EMA, 'ema', ctx.type, function (indicator) {
- indicator.prototype.init.apply(ctx, args);
- return;
- });
- },
- getValues: function (series, params) {
- var periods = params.periods,
- period = params.period,
- // Accumulation Distribution Line data
- ADL,
- // 0- date, 1- Chaikin Oscillator
- CHA = [],
- xData = [],
- yData = [],
- periodsOffset,
- // Shorter Period EMA
- SPE,
- // Longer Period EMA
- LPE,
- oscillator,
- i;
- // Check if periods are correct
- if (periods.length !== 2 || periods[1] <= periods[0]) {
- error('Error: "Chaikin requires two periods. Notice, first ' +
- 'period should be lower than the second one."');
- return;
- }
- ADL = AD.prototype.getValues.call(this, series, {
- volumeSeriesID: params.volumeSeriesID,
- period: period
- });
- // Check if adl is calculated properly, if not skip
- if (!ADL) {
- return;
- }
- SPE = EMA.prototype.getValues.call(this, ADL, {
- period: periods[0]
- });
- LPE = EMA.prototype.getValues.call(this, ADL, {
- period: periods[1]
- });
- // Check if ema is calculated properly, if not skip
- if (!SPE || !LPE) {
- return;
- }
- periodsOffset = periods[1] - periods[0];
- for (i = 0; i < LPE.yData.length; i++) {
- oscillator = correctFloat(SPE.yData[i + periodsOffset] -
- LPE.yData[i]);
- CHA.push([LPE.xData[i], oscillator]);
- xData.push(LPE.xData[i]);
- yData.push(oscillator);
- }
- return {
- values: CHA,
- xData: xData,
- yData: yData
- };
- }
- });
- /**
- * A `Chaikin Oscillator` series. If the [type](#series.chaikin.type)
- * option is not specified, it is inherited from [chart.type](#chart.type).
- *
- * @extends series,plotOptions.chaikin
- * @since 7.0.0
- * @product highstock
- * @excluding allAreas, colorAxis, dataParser, dataURL, joinBy, keys,
- * navigatorOptions, pointInterval, pointIntervalUnit,
- * pointPlacement, pointRange, pointStart, stacking, showInNavigator
- * @requires stock/indicators/indicators
- * @requires stock/indicators/ema
- * @requires stock/indicators/chaikin
- * @apioption series.chaikin
- */
- ''; // to include the above in the js output
- });
- _registerModule(_modules, 'Stock/Indicators/DEMAIndicator.js', [_modules['Core/Globals.js'], _modules['Core/Utilities.js'], _modules['Mixins/IndicatorRequired.js']], function (H, U, requiredIndicator) {
- /* *
- *
- * License: www.highcharts.com/license
- *
- * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
- *
- * */
- var correctFloat = U.correctFloat,
- isArray = U.isArray,
- seriesType = U.seriesType;
- var EMAindicator = H.seriesTypes.ema;
- /**
- * The DEMA series Type
- *
- * @private
- * @class
- * @name Highcharts.seriesTypes.dema
- *
- * @augments Highcharts.Series
- */
- seriesType('dema', 'ema',
- /**
- * Double exponential moving average (DEMA) indicator. This series requires
- * `linkedTo` option to be set and should be loaded after the
- * `stock/indicators/indicators.js` and `stock/indicators/ema.js`.
- *
- * @sample {highstock} stock/indicators/dema
- * DEMA indicator
- *
- * @extends plotOptions.ema
- * @since 7.0.0
- * @product highstock
- * @excluding allAreas, colorAxis, compare, compareBase, joinBy, keys,
- * navigatorOptions, pointInterval, pointIntervalUnit,
- * pointPlacement, pointRange, pointStart, showInNavigator,
- * stacking
- * @requires stock/indicators/indicators
- * @requires stock/indicators/ema
- * @requires stock/indicators/dema
- * @optionparent plotOptions.dema
- */
- {},
- /**
- * @lends Highcharts.Series#
- */
- {
- init: function () {
- var args = arguments,
- ctx = this;
- requiredIndicator.isParentLoaded(EMAindicator, 'ema', ctx.type, function (indicator) {
- indicator.prototype.init.apply(ctx, args);
- return;
- });
- },
- getEMA: function (yVal, prevEMA, SMA, index, i, xVal) {
- return EMAindicator.prototype.calculateEma(xVal || [], yVal, typeof i === 'undefined' ? 1 : i, this.chart.series[0].EMApercent, prevEMA, typeof index === 'undefined' ? -1 : index, SMA);
- },
- getValues: function (series, params) {
- var period = params.period,
- doubledPeriod = 2 * period,
- xVal = series.xData,
- yVal = series.yData,
- yValLen = yVal ? yVal.length : 0,
- index = -1,
- accumulatePeriodPoints = 0,
- SMA = 0,
- DEMA = [],
- xDataDema = [],
- yDataDema = [],
- EMA = 0,
- // EMA(EMA)
- EMAlevel2,
- // EMA of previous point
- prevEMA,
- prevEMAlevel2,
- // EMA values array
- EMAvalues = [],
- i,
- DEMAPoint;
- series.EMApercent = (2 / (period + 1));
- // Check period, if bigger than EMA points length, skip
- if (yValLen < 2 * period - 1) {
- return;
- }
- // Switch index for OHLC / Candlestick / Arearange
- if (isArray(yVal[0])) {
- index = params.index ? params.index : 0;
- }
- // Accumulate first N-points
- accumulatePeriodPoints =
- EMAindicator.prototype.accumulatePeriodPoints(period, index, yVal);
- // first point
- SMA = accumulatePeriodPoints / period;
- accumulatePeriodPoints = 0;
- // Calculate value one-by-one for each period in visible data
- for (i = period; i < yValLen + 2; i++) {
- if (i < yValLen + 1) {
- EMA = this.getEMA(yVal, prevEMA, SMA, index, i)[1];
- EMAvalues.push(EMA);
- }
- prevEMA = EMA;
- // Summing first period points for EMA(EMA)
- if (i < doubledPeriod) {
- accumulatePeriodPoints += EMA;
- }
- else {
- // Calculate DEMA
- // First DEMA point
- if (i === doubledPeriod) {
- SMA = accumulatePeriodPoints / period;
- }
- EMA = EMAvalues[i - period - 1];
- EMAlevel2 = this.getEMA([EMA], prevEMAlevel2, SMA)[1];
- DEMAPoint = [
- xVal[i - 2],
- correctFloat(2 * EMA - EMAlevel2)
- ];
- DEMA.push(DEMAPoint);
- xDataDema.push(DEMAPoint[0]);
- yDataDema.push(DEMAPoint[1]);
- prevEMAlevel2 = EMAlevel2;
- }
- }
- return {
- values: DEMA,
- xData: xDataDema,
- yData: yDataDema
- };
- }
- });
- /**
- * A `DEMA` series. If the [type](#series.ema.type) option is not
- * specified, it is inherited from [chart.type](#chart.type).
- *
- * @extends series,plotOptions.ema
- * @since 7.0.0
- * @product highstock
- * @excluding allAreas, colorAxis, compare, compareBase, dataParser, dataURL,
- * joinBy, keys, navigatorOptions, pointInterval, pointIntervalUnit,
- * pointPlacement, pointRange, pointStart, showInNavigator, stacking
- * @requires stock/indicators/indicators
- * @requires stock/indicators/ema
- * @requires stock/indicators/dema
- * @apioption series.dema
- */
- ''; // adds doclet above to the transpiled file
- });
- _registerModule(_modules, 'Stock/Indicators/TEMAIndicator.js', [_modules['Core/Globals.js'], _modules['Core/Utilities.js'], _modules['Mixins/IndicatorRequired.js']], function (H, U, requiredIndicator) {
- /* *
- *
- * License: www.highcharts.com/license
- *
- * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
- *
- * */
- var correctFloat = U.correctFloat,
- isArray = U.isArray,
- seriesType = U.seriesType;
- var EMAindicator = H.seriesTypes.ema;
- /**
- * The TEMA series type.
- *
- * @private
- * @class
- * @name Highcharts.seriesTypes.tema
- *
- * @augments Highcharts.Series
- */
- seriesType('tema', 'ema',
- /**
- * Triple exponential moving average (TEMA) indicator. This series requires
- * `linkedTo` option to be set and should be loaded after the
- * `stock/indicators/indicators.js` and `stock/indicators/ema.js`.
- *
- * @sample {highstock} stock/indicators/tema
- * TEMA indicator
- *
- * @extends plotOptions.ema
- * @since 7.0.0
- * @product highstock
- * @excluding allAreas, colorAxis, compare, compareBase, joinBy, keys,
- * navigatorOptions, pointInterval, pointIntervalUnit,
- * pointPlacement, pointRange, pointStart, showInNavigator,
- * stacking
- * @requires stock/indicators/indicators
- * @requires stock/indicators/ema
- * @requires stock/indicators/tema
- * @optionparent plotOptions.tema
- */
- {},
- /**
- * @lends Highcharts.Series#
- */
- {
- init: function () {
- var args = arguments,
- ctx = this;
- requiredIndicator.isParentLoaded(EMAindicator, 'ema', ctx.type, function (indicator) {
- indicator.prototype.init.apply(ctx, args);
- return;
- });
- },
- getEMA: function (yVal, prevEMA, SMA, index, i, xVal) {
- return EMAindicator.prototype.calculateEma(xVal || [], yVal, typeof i === 'undefined' ? 1 : i, this.chart.series[0].EMApercent, prevEMA, typeof index === 'undefined' ? -1 : index, SMA);
- },
- getTemaPoint: function (xVal, tripledPeriod, EMAlevels, i) {
- var TEMAPoint = [
- xVal[i - 3],
- correctFloat(3 * EMAlevels.level1 -
- 3 * EMAlevels.level2 + EMAlevels.level3)
- ];
- return TEMAPoint;
- },
- getValues: function (series, params) {
- var period = params.period,
- doubledPeriod = 2 * period,
- tripledPeriod = 3 * period,
- xVal = series.xData,
- yVal = series.yData,
- yValLen = yVal ? yVal.length : 0,
- index = -1,
- accumulatePeriodPoints = 0,
- SMA = 0,
- TEMA = [],
- xDataTema = [],
- yDataTema = [],
- // EMA of previous point
- prevEMA,
- prevEMAlevel2,
- // EMA values array
- EMAvalues = [],
- EMAlevel2values = [],
- i,
- TEMAPoint,
- // This object contains all EMA EMAlevels calculated like below
- // EMA = level1
- // EMA(EMA) = level2,
- // EMA(EMA(EMA)) = level3,
- EMAlevels = {};
- series.EMApercent = (2 / (period + 1));
- // Check period, if bigger than EMA points length, skip
- if (yValLen < 3 * period - 2) {
- return;
- }
- // Switch index for OHLC / Candlestick / Arearange
- if (isArray(yVal[0])) {
- index = params.index ? params.index : 0;
- }
- // Accumulate first N-points
- accumulatePeriodPoints =
- EMAindicator.prototype.accumulatePeriodPoints(period, index, yVal);
- // first point
- SMA = accumulatePeriodPoints / period;
- accumulatePeriodPoints = 0;
- // Calculate value one-by-one for each period in visible data
- for (i = period; i < yValLen + 3; i++) {
- if (i < yValLen + 1) {
- EMAlevels.level1 = this.getEMA(yVal, prevEMA, SMA, index, i)[1];
- EMAvalues.push(EMAlevels.level1);
- }
- prevEMA = EMAlevels.level1;
- // Summing first period points for ema(ema)
- if (i < doubledPeriod) {
- accumulatePeriodPoints += EMAlevels.level1;
- }
- else {
- // Calculate dema
- // First dema point
- if (i === doubledPeriod) {
- SMA = accumulatePeriodPoints / period;
- accumulatePeriodPoints = 0;
- }
- EMAlevels.level1 = EMAvalues[i - period - 1];
- EMAlevels.level2 = this.getEMA([EMAlevels.level1], prevEMAlevel2, SMA)[1];
- EMAlevel2values.push(EMAlevels.level2);
- prevEMAlevel2 = EMAlevels.level2;
- // Summing first period points for ema(ema(ema))
- if (i < tripledPeriod) {
- accumulatePeriodPoints += EMAlevels.level2;
- }
- else {
- // Calculate tema
- // First tema point
- if (i === tripledPeriod) {
- SMA = accumulatePeriodPoints / period;
- }
- if (i === yValLen + 1) {
- // Calculate the last ema and emaEMA points
- EMAlevels.level1 = EMAvalues[i - period - 1];
- EMAlevels.level2 = this.getEMA([EMAlevels.level1], prevEMAlevel2, SMA)[1];
- EMAlevel2values.push(EMAlevels.level2);
- }
- EMAlevels.level1 = EMAvalues[i - period - 2];
- EMAlevels.level2 = EMAlevel2values[i - 2 * period - 1];
- EMAlevels.level3 = this.getEMA([EMAlevels.level2], EMAlevels.prevLevel3, SMA)[1];
- TEMAPoint = this.getTemaPoint(xVal, tripledPeriod, EMAlevels, i);
- // Make sure that point exists (for TRIX oscillator)
- if (TEMAPoint) {
- TEMA.push(TEMAPoint);
- xDataTema.push(TEMAPoint[0]);
- yDataTema.push(TEMAPoint[1]);
- }
- EMAlevels.prevLevel3 = EMAlevels.level3;
- }
- }
- }
- return {
- values: TEMA,
- xData: xDataTema,
- yData: yDataTema
- };
- }
- });
- /**
- * A `TEMA` series. If the [type](#series.ema.type) option is not
- * specified, it is inherited from [chart.type](#chart.type).
- *
- * @extends series,plotOptions.ema
- * @since 7.0.0
- * @product highstock
- * @excluding allAreas, colorAxis, compare, compareBase, dataParser, dataURL,
- * joinBy, keys, navigatorOptions, pointInterval, pointIntervalUnit,
- * pointPlacement, pointRange, pointStart, showInNavigator, stacking
- * @requires stock/indicators/indicators
- * @requires stock/indicators/ema
- * @requires stock/indicators/tema
- * @apioption series.tema
- */
- ''; // to include the above in the js output
- });
- _registerModule(_modules, 'Stock/Indicators/TRIXIndicator.js', [_modules['Core/Globals.js'], _modules['Core/Utilities.js'], _modules['Mixins/IndicatorRequired.js']], function (H, U, requiredIndicator) {
- /* *
- *
- * License: www.highcharts.com/license
- *
- * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
- *
- * */
- var correctFloat = U.correctFloat,
- seriesType = U.seriesType;
- var TEMA = H.seriesTypes.tema;
- /**
- * The TRIX series type.
- *
- * @private
- * @class
- * @name Highcharts.seriesTypes.trix
- *
- * @augments Highcharts.Series
- */
- seriesType('trix', 'tema',
- /**
- * Triple exponential average (TRIX) oscillator. This series requires
- * `linkedTo` option to be set.
- *
- * Requires https://code.highcharts.com/stock/indicators/ema.js
- * and https://code.highcharts.com/stock/indicators/tema.js.
- *
- * @sample {highstock} stock/indicators/trix
- * TRIX indicator
- *
- * @extends plotOptions.tema
- * @since 7.0.0
- * @product highstock
- * @excluding allAreas, colorAxis, compare, compareBase, joinBy, keys,
- * navigatorOptions, pointInterval, pointIntervalUnit,
- * pointPlacement, pointRange, pointStart, showInNavigator,
- * stacking
- * @optionparent plotOptions.trix
- */
- {},
- /**
- * @lends Highcharts.Series#
- */
- {
- init: function () {
- var args = arguments,
- ctx = this;
- requiredIndicator.isParentLoaded(TEMA, 'tema', ctx.type, function (indicator) {
- indicator.prototype.init.apply(ctx, args);
- return;
- });
- },
- // TRIX is calculated using TEMA so we just extend getTemaPoint method.
- getTemaPoint: function (xVal, tripledPeriod, EMAlevels, i) {
- if (i > tripledPeriod) {
- var TRIXPoint = [
- xVal[i - 3],
- EMAlevels.prevLevel3 !== 0 ?
- correctFloat(EMAlevels.level3 - EMAlevels.prevLevel3) /
- EMAlevels.prevLevel3 * 100 : null
- ];
- }
- return TRIXPoint;
- }
- });
- /**
- * A `TRIX` series. If the [type](#series.tema.type) option is not specified, it
- * is inherited from [chart.type](#chart.type).
- *
- * @extends series,plotOptions.tema
- * @since 7.0.0
- * @product highstock
- * @excluding allAreas, colorAxis, compare, compareBase, dataParser, dataURL,
- * joinBy, keys, navigatorOptions, pointInterval, pointIntervalUnit,
- * pointPlacement, pointRange, pointStart, showInNavigator, stacking
- * @apioption series.trix
- */
- ''; // to include the above in the js output
- });
- _registerModule(_modules, 'Stock/Indicators/APOIndicator.js', [_modules['Core/Globals.js'], _modules['Core/Utilities.js'], _modules['Mixins/IndicatorRequired.js']], function (H, U, requiredIndicator) {
- /* *
- *
- * License: www.highcharts.com/license
- *
- * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
- *
- * */
- var error = U.error,
- seriesType = U.seriesType;
- var EMA = H.seriesTypes.ema;
- /**
- * The APO series type.
- *
- * @private
- * @class
- * @name Highcharts.seriesTypes.apo
- *
- * @augments Highcharts.Series
- */
- seriesType('apo', 'ema',
- /**
- * Absolute Price Oscillator. This series requires the `linkedTo` option to
- * be set and should be loaded after the `stock/indicators/indicators.js`
- * and `stock/indicators/ema.js`.
- *
- * @sample {highstock} stock/indicators/apo
- * Absolute Price Oscillator
- *
- * @extends plotOptions.ema
- * @since 7.0.0
- * @product highstock
- * @excluding allAreas, colorAxis, joinBy, keys, navigatorOptions,
- * pointInterval, pointIntervalUnit, pointPlacement,
- * pointRange, pointStart, showInNavigator, stacking
- * @requires stock/indicators/indicators
- * @requires stock/indicators/ema
- * @requires stock/indicators/apo
- * @optionparent plotOptions.apo
- */
- {
- /**
- * Paramters used in calculation of Absolute Price Oscillator
- * series points.
- *
- * @excluding period
- */
- params: {
- /**
- * Periods for Absolute Price Oscillator calculations.
- *
- * @type {Array<number>}
- * @default [10, 20]
- * @since 7.0.0
- */
- periods: [10, 20]
- }
- },
- /**
- * @lends Highcharts.Series.prototype
- */
- {
- nameBase: 'APO',
- nameComponents: ['periods'],
- init: function () {
- var args = arguments,
- ctx = this;
- requiredIndicator.isParentLoaded(EMA, 'ema', ctx.type, function (indicator) {
- indicator.prototype.init.apply(ctx, args);
- return;
- });
- },
- getValues: function (series, params) {
- var periods = params.periods,
- index = params.index,
- // 0- date, 1- Absolute price oscillator
- APO = [],
- xData = [],
- yData = [],
- periodsOffset,
- // Shorter Period EMA
- SPE,
- // Longer Period EMA
- LPE,
- oscillator,
- i;
- // Check if periods are correct
- if (periods.length !== 2 || periods[1] <= periods[0]) {
- error('Error: "APO requires two periods. Notice, first period ' +
- 'should be lower than the second one."');
- return;
- }
- SPE = EMA.prototype.getValues.call(this, series, {
- index: index,
- period: periods[0]
- });
- LPE = EMA.prototype.getValues.call(this, series, {
- index: index,
- period: periods[1]
- });
- // Check if ema is calculated properly, if not skip
- if (!SPE || !LPE) {
- return;
- }
- periodsOffset = periods[1] - periods[0];
- for (i = 0; i < LPE.yData.length; i++) {
- oscillator = (SPE.yData[i + periodsOffset] -
- LPE.yData[i]);
- APO.push([LPE.xData[i], oscillator]);
- xData.push(LPE.xData[i]);
- yData.push(oscillator);
- }
- return {
- values: APO,
- xData: xData,
- yData: yData
- };
- }
- });
- /**
- * An `Absolute Price Oscillator` series. If the [type](#series.apo.type) option
- * is not specified, it is inherited from [chart.type](#chart.type).
- *
- * @extends series,plotOptions.apo
- * @since 7.0.0
- * @product highstock
- * @excluding allAreas, colorAxis, dataParser, dataURL, joinBy, keys,
- * navigatorOptions, pointInterval, pointIntervalUnit,
- * pointPlacement, pointRange, pointStart, showInNavigator, stacking
- * @requires stock/indicators/indicators
- * @requires stock/indicators/ema
- * @requires stock/indicators/apo
- * @apioption series.apo
- */
- ''; // to include the above in the js output
- });
- _registerModule(_modules, 'Stock/Indicators/IKHIndicator.js', [_modules['Core/Globals.js'], _modules['Core/Color.js'], _modules['Core/Utilities.js']], function (H, Color, U) {
- /* *
- *
- * License: www.highcharts.com/license
- *
- * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
- *
- * */
- /* eslint-enable @typescript-eslint/interface-name-prefix */
- var color = Color.parse;
- var defined = U.defined,
- isArray = U.isArray,
- merge = U.merge,
- objectEach = U.objectEach,
- seriesType = U.seriesType;
- var UNDEFINED,
- SMA = H.seriesTypes.sma;
- /* eslint-disable require-jsdoc */
- // Utils:
- function maxHigh(arr) {
- return arr.reduce(function (max, res) {
- return Math.max(max, res[1]);
- }, -Infinity);
- }
- function minLow(arr) {
- return arr.reduce(function (min, res) {
- return Math.min(min, res[2]);
- }, Infinity);
- }
- function highlowLevel(arr) {
- return {
- high: maxHigh(arr),
- low: minLow(arr)
- };
- }
- function getClosestPointRange(axis) {
- var closestDataRange,
- loopLength,
- distance,
- xData,
- i;
- axis.series.forEach(function (series) {
- if (series.xData) {
- xData = series.xData;
- loopLength = series.xIncrement ? 1 : xData.length - 1;
- for (i = loopLength; i > 0; i--) {
- distance = xData[i] - xData[i - 1];
- if (closestDataRange === UNDEFINED ||
- distance < closestDataRange) {
- closestDataRange = distance;
- }
- }
- }
- });
- return closestDataRange;
- }
- // Check two lines intersection (line a1-a2 and b1-b2)
- // Source: https://en.wikipedia.org/wiki/Line%E2%80%93line_intersection
- function checkLineIntersection(a1, a2, b1, b2) {
- if (a1 && a2 && b1 && b2) {
- var saX = a2.plotX - a1.plotX, // Auxiliary section a2-a1 X
- saY = a2.plotY - a1.plotY, // Auxiliary section a2-a1 Y
- sbX = b2.plotX - b1.plotX, // Auxiliary section b2-b1 X
- sbY = b2.plotY - b1.plotY, // Auxiliary section b2-b1 Y
- sabX = a1.plotX - b1.plotX, // Auxiliary section a1-b1 X
- sabY = a1.plotY - b1.plotY, // Auxiliary section a1-b1 Y
- // First degree Bézier parameters
- u,
- t;
- u = (-saY * sabX + saX * sabY) / (-sbX * saY + saX * sbY);
- t = (sbX * sabY - sbY * sabX) / (-sbX * saY + saX * sbY);
- if (u >= 0 && u <= 1 && t >= 0 && t <= 1) {
- return {
- plotX: a1.plotX + (t * saX),
- plotY: a1.plotY + (t * saY)
- };
- }
- }
- return false;
- }
- // Parameter opt (indicator options object) include indicator, points,
- // nextPoints, color, options, gappedExtend and graph properties
- function drawSenkouSpan(opt) {
- var indicator = opt.indicator;
- indicator.points = opt.points;
- indicator.nextPoints = opt.nextPoints;
- indicator.color = opt.color;
- indicator.options = merge(opt.options.senkouSpan.styles, opt.gap);
- indicator.graph = opt.graph;
- indicator.fillGraph = true;
- SMA.prototype.drawGraph.call(indicator);
- }
- // Data integrity in Ichimoku is different than default "averages":
- // Point: [undefined, value, value, ...] is correct
- // Point: [undefined, undefined, undefined, ...] is incorrect
- H.approximations['ichimoku-averages'] = function () {
- var ret = [],
- isEmptyRange;
- [].forEach.call(arguments, function (arr, i) {
- ret.push(H.approximations.average(arr));
- isEmptyRange = !isEmptyRange && typeof ret[i] === 'undefined';
- });
- // Return undefined when first elem. is undefined and let
- // sum method handle null (#7377)
- return isEmptyRange ? void 0 : ret;
- };
- /* eslint-enable require-jsdoc */
- /**
- * The IKH series type.
- *
- * @private
- * @class
- * @name Highcharts.seriesTypes.ikh
- *
- * @augments Highcharts.Series
- */
- seriesType('ikh', 'sma',
- /**
- * Ichimoku Kinko Hyo (IKH). This series requires `linkedTo` option to be
- * set.
- *
- * @sample stock/indicators/ichimoku-kinko-hyo
- * Ichimoku Kinko Hyo indicator
- *
- * @extends plotOptions.sma
- * @since 6.0.0
- * @excluding allAreas, colorAxis, compare, compareBase, joinBy, keys,
- * navigatorOptions, pointInterval, pointIntervalUnit,
- * pointPlacement, pointRange, pointStart, showInNavigator,
- * stacking
- * @product highstock
- * @requires stock/indicators/indicators
- * @requires stock/indicators/ichimoku-kinko-hyo
- * @optionparent plotOptions.ikh
- */
- {
- params: {
- period: 26,
- /**
- * The base period for Tenkan calculations.
- */
- periodTenkan: 9,
- /**
- * The base period for Senkou Span B calculations
- */
- periodSenkouSpanB: 52
- },
- marker: {
- enabled: false
- },
- tooltip: {
- pointFormat: '<span style="color:{point.color}">\u25CF</span> <b> {series.name}</b><br/>' +
- 'TENKAN SEN: {point.tenkanSen:.3f}<br/>' +
- 'KIJUN SEN: {point.kijunSen:.3f}<br/>' +
- 'CHIKOU SPAN: {point.chikouSpan:.3f}<br/>' +
- 'SENKOU SPAN A: {point.senkouSpanA:.3f}<br/>' +
- 'SENKOU SPAN B: {point.senkouSpanB:.3f}<br/>'
- },
- /**
- * The styles for Tenkan line
- */
- tenkanLine: {
- styles: {
- /**
- * Pixel width of the line.
- */
- lineWidth: 1,
- /**
- * Color of the line.
- *
- * @type {Highcharts.ColorString}
- */
- lineColor: void 0
- }
- },
- /**
- * The styles for Kijun line
- */
- kijunLine: {
- styles: {
- /**
- * Pixel width of the line.
- */
- lineWidth: 1,
- /**
- * Color of the line.
- *
- * @type {Highcharts.ColorString}
- */
- lineColor: void 0
- }
- },
- /**
- * The styles for Chikou line
- */
- chikouLine: {
- styles: {
- /**
- * Pixel width of the line.
- */
- lineWidth: 1,
- /**
- * Color of the line.
- *
- * @type {Highcharts.ColorString}
- */
- lineColor: void 0
- }
- },
- /**
- * The styles for Senkou Span A line
- */
- senkouSpanA: {
- styles: {
- /**
- * Pixel width of the line.
- */
- lineWidth: 1,
- /**
- * Color of the line.
- *
- * @type {Highcharts.ColorString}
- */
- lineColor: void 0
- }
- },
- /**
- * The styles for Senkou Span B line
- */
- senkouSpanB: {
- styles: {
- /**
- * Pixel width of the line.
- */
- lineWidth: 1,
- /**
- * Color of the line.
- *
- * @type {Highcharts.ColorString}
- */
- lineColor: void 0
- }
- },
- /**
- * The styles for area between Senkou Span A and B.
- */
- senkouSpan: {
- /**
- * Color of the area between Senkou Span A and B,
- * when Senkou Span A is above Senkou Span B. Note that if
- * a `style.fill` is defined, the `color` takes precedence and
- * the `style.fill` is ignored.
- *
- * @see [senkouSpan.styles.fill](#series.ikh.senkouSpan.styles.fill)
- *
- * @sample stock/indicators/ichimoku-kinko-hyo
- * Ichimoku Kinko Hyo color
- *
- * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
- * @since 7.0.0
- * @apioption plotOptions.ikh.senkouSpan.color
- */
- /**
- * Color of the area between Senkou Span A and B,
- * when Senkou Span A is under Senkou Span B.
- *
- * @sample stock/indicators/ikh-negative-color
- * Ichimoku Kinko Hyo negativeColor
- *
- * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
- * @since 7.0.0
- * @apioption plotOptions.ikh.senkouSpan.negativeColor
- */
- styles: {
- /**
- * Color of the area between Senkou Span A and B.
- *
- * @deprecated
- * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
- */
- fill: 'rgba(255, 0, 0, 0.5)'
- }
- },
- dataGrouping: {
- approximation: 'ichimoku-averages'
- }
- },
- /**
- * @lends Highcharts.Series#
- */
- {
- pointArrayMap: [
- 'tenkanSen',
- 'kijunSen',
- 'chikouSpan',
- 'senkouSpanA',
- 'senkouSpanB'
- ],
- pointValKey: 'tenkanSen',
- nameComponents: ['periodSenkouSpanB', 'period', 'periodTenkan'],
- init: function () {
- SMA.prototype.init.apply(this, arguments);
- // Set default color for lines:
- this.options = merge({
- tenkanLine: {
- styles: {
- lineColor: this.color
- }
- },
- kijunLine: {
- styles: {
- lineColor: this.color
- }
- },
- chikouLine: {
- styles: {
- lineColor: this.color
- }
- },
- senkouSpanA: {
- styles: {
- lineColor: this.color,
- fill: color(this.color).setOpacity(0.5).get()
- }
- },
- senkouSpanB: {
- styles: {
- lineColor: this.color,
- fill: color(this.color).setOpacity(0.5).get()
- }
- },
- senkouSpan: {
- styles: {
- fill: color(this.color).setOpacity(0.2).get()
- }
- }
- }, this.options);
- },
- toYData: function (point) {
- return [
- point.tenkanSen,
- point.kijunSen,
- point.chikouSpan,
- point.senkouSpanA,
- point.senkouSpanB
- ];
- },
- translate: function () {
- var indicator = this;
- SMA.prototype.translate.apply(indicator);
- indicator.points.forEach(function (point) {
- indicator.pointArrayMap.forEach(function (value) {
- if (defined(point[value])) {
- point['plot' + value] =
- indicator.yAxis.toPixels(point[value], true);
- // Add extra parameters for support tooltip in moved
- // lines
- point.plotY = point['plot' + value];
- point.tooltipPos = [
- point.plotX,
- point['plot' + value]
- ];
- point.isNull = false;
- }
- });
- });
- },
- // One does not simply
- // Render five linesZ
- // And an arearange
- // In just one series..
- drawGraph: function () {
- var indicator = this,
- mainLinePoints = (indicator.points),
- pointsLength = mainLinePoints.length,
- mainLineOptions = (indicator.options),
- mainLinePath = (indicator.graph),
- mainColor = indicator.color,
- gappedExtend = {
- options: {
- gapSize: mainLineOptions.gapSize
- }
- },
- pointArrayMapLength = indicator.pointArrayMap.length,
- allIchimokuPoints = [[],
- [],
- [],
- [],
- [],
- []],
- ikhMap = {
- tenkanLine: allIchimokuPoints[0],
- kijunLine: allIchimokuPoints[1],
- chikouLine: allIchimokuPoints[2],
- senkouSpanA: allIchimokuPoints[3],
- senkouSpanB: allIchimokuPoints[4],
- senkouSpan: allIchimokuPoints[5]
- },
- intersectIndexColl = [],
- senkouSpanOptions = indicator.options.senkouSpan,
- color = (senkouSpanOptions.color ||
- senkouSpanOptions.styles.fill),
- negativeColor = (senkouSpanOptions.negativeColor),
- // Points to create color and negativeColor senkouSpan
- points = [
- [],
- [] // Points negative color
- ],
- // For span, we need an access to the next points, used in
- // getGraphPath()
- nextPoints = [
- [],
- [] // NextPoints negative color
- ],
- lineIndex = 0,
- position,
- point,
- i,
- startIntersect,
- endIntersect,
- sectionPoints,
- sectionNextPoints,
- pointsPlotYSum,
- nextPointsPlotYSum,
- senkouSpanTempColor,
- concatArrIndex,
- j,
- k;
- indicator.ikhMap = ikhMap;
- // Generate points for all lines and spans lines:
- while (pointsLength--) {
- point = mainLinePoints[pointsLength];
- for (i = 0; i < pointArrayMapLength; i++) {
- position = indicator.pointArrayMap[i];
- if (defined(point[position])) {
- allIchimokuPoints[i].push({
- plotX: point.plotX,
- plotY: point['plot' + position],
- isNull: false
- });
- }
- }
- if (negativeColor &&
- pointsLength !== mainLinePoints.length - 1) {
- // Check if lines intersect
- var index = ikhMap.senkouSpanB.length - 1,
- intersect = checkLineIntersection(ikhMap.senkouSpanA[index - 1],
- ikhMap.senkouSpanA[index],
- ikhMap.senkouSpanB[index - 1],
- ikhMap.senkouSpanB[index]),
- intersectPointObj = {
- plotX: intersect.plotX,
- plotY: intersect.plotY,
- isNull: false,
- intersectPoint: true
- };
- if (intersect) {
- // Add intersect point to ichimoku points collection
- // Create senkouSpan sections
- ikhMap.senkouSpanA.splice(index, 0, intersectPointObj);
- ikhMap.senkouSpanB.splice(index, 0, intersectPointObj);
- intersectIndexColl.push(index);
- }
- }
- }
- // Modify options and generate lines:
- objectEach(ikhMap, function (values, lineName) {
- if (mainLineOptions[lineName] &&
- lineName !== 'senkouSpan') {
- // First line is rendered by default option
- indicator.points = allIchimokuPoints[lineIndex];
- indicator.options = merge(mainLineOptions[lineName].styles, gappedExtend);
- indicator.graph = indicator['graph' + lineName];
- indicator.fillGraph = false;
- indicator.color = mainColor;
- SMA.prototype.drawGraph.call(indicator);
- // Now save line
- indicator['graph' + lineName] = indicator.graph;
- }
- lineIndex++;
- });
- // Generate senkouSpan area:
- // If graphColection exist then remove svg
- // element and indicator property
- if (indicator.graphCollection) {
- indicator.graphCollection.forEach(function (graphName) {
- indicator[graphName].destroy();
- delete indicator[graphName];
- });
- }
- // Clean grapCollection or initialize it
- indicator.graphCollection = [];
- // When user set negativeColor property
- if (negativeColor &&
- ikhMap.senkouSpanA[0] &&
- ikhMap.senkouSpanB[0]) {
- // Add first and last point to senkouSpan area sections
- intersectIndexColl.unshift(0);
- intersectIndexColl.push(ikhMap.senkouSpanA.length - 1);
- // Populate points and nextPoints arrays
- for (j = 0; j < intersectIndexColl.length - 1; j++) {
- startIntersect = intersectIndexColl[j];
- endIntersect = intersectIndexColl[j + 1];
- sectionPoints = ikhMap.senkouSpanB.slice(startIntersect, endIntersect + 1);
- sectionNextPoints = ikhMap.senkouSpanA.slice(startIntersect, endIntersect + 1);
- // Add points to color or negativeColor arrays
- // Check the middle point (if exist)
- if (Math.floor(sectionPoints.length / 2) >= 1) {
- var x = Math.floor(sectionPoints.length / 2);
- // When middle points has equal values
- // Compare all ponints plotY value sum
- if (sectionPoints[x].plotY ===
- sectionNextPoints[x].plotY) {
- pointsPlotYSum = 0;
- nextPointsPlotYSum = 0;
- for (k = 0; k < sectionPoints.length; k++) {
- pointsPlotYSum +=
- sectionPoints[k].plotY;
- nextPointsPlotYSum +=
- sectionNextPoints[k].plotY;
- }
- concatArrIndex = (pointsPlotYSum > nextPointsPlotYSum ? 0 : 1);
- points[concatArrIndex] = (points[concatArrIndex].concat(sectionPoints));
- nextPoints[concatArrIndex] = (nextPoints[concatArrIndex].concat(sectionNextPoints));
- }
- else {
- // Compare middle point of the section
- concatArrIndex = (sectionPoints[x].plotY >
- sectionNextPoints[x].plotY ?
- 0 : 1);
- points[concatArrIndex] = (points[concatArrIndex].concat(sectionPoints));
- nextPoints[concatArrIndex] = (nextPoints[concatArrIndex].concat(sectionNextPoints));
- }
- }
- else {
- // Compare first point of the section
- concatArrIndex = (sectionPoints[0].plotY >
- sectionNextPoints[0].plotY ?
- 0 : 1);
- points[concatArrIndex] = (points[concatArrIndex].concat(sectionPoints));
- nextPoints[concatArrIndex] = (nextPoints[concatArrIndex].concat(sectionNextPoints));
- }
- }
- // Render color and negativeColor paths
- [
- 'graphsenkouSpanColor', 'graphsenkouSpanNegativeColor'
- ].forEach(function (areaName, i) {
- if (points[i].length && nextPoints[i].length) {
- senkouSpanTempColor = (i === 0) ?
- color : negativeColor;
- drawSenkouSpan({
- indicator: indicator,
- points: points[i],
- nextPoints: nextPoints[i],
- color: senkouSpanTempColor,
- options: mainLineOptions,
- gap: gappedExtend,
- graph: indicator[areaName]
- });
- // Now save line
- indicator[areaName] = indicator.graph;
- indicator.graphCollection.push(areaName);
- }
- });
- }
- else {
- // When user set only senkouSpan style.fill property
- drawSenkouSpan({
- indicator: indicator,
- points: ikhMap.senkouSpanB,
- nextPoints: ikhMap.senkouSpanA,
- color: color,
- options: mainLineOptions,
- gap: gappedExtend,
- graph: indicator.graphsenkouSpan
- });
- // Now save line
- indicator.graphsenkouSpan = indicator.graph;
- }
- // Clean temporary properties:
- delete indicator.nextPoints;
- delete indicator.fillGraph;
- // Restore options and draw the Tenkan line:
- indicator.points = mainLinePoints;
- indicator.options = mainLineOptions;
- indicator.graph = mainLinePath;
- },
- getGraphPath: function (points) {
- var indicator = this,
- path = [],
- spanA,
- spanAarr = [];
- points = points || this.points;
- // Render Senkou Span
- if (indicator.fillGraph && indicator.nextPoints) {
- spanA = SMA.prototype.getGraphPath.call(indicator,
- // Reverse points, so Senkou Span A will start from the end:
- indicator.nextPoints);
- spanA[0][0] = 'L';
- path = SMA.prototype.getGraphPath.call(indicator, points);
- spanAarr = spanA.slice(0, path.length);
- for (var i = spanAarr.length - 1; i >= 0; i--) {
- path.push(spanAarr[i]);
- }
- }
- else {
- path = SMA.prototype.getGraphPath.apply(indicator, arguments);
- }
- return path;
- },
- getValues: function (series, params) {
- var period = params.period,
- periodTenkan = params.periodTenkan,
- periodSenkouSpanB = params.periodSenkouSpanB,
- xVal = series.xData,
- yVal = series.yData,
- xAxis = series.xAxis,
- yValLen = (yVal && yVal.length) || 0,
- closestPointRange = getClosestPointRange(xAxis),
- IKH = [],
- xData = [],
- dateStart,
- date,
- slicedTSY,
- slicedKSY,
- slicedSSBY,
- pointTS,
- pointKS,
- pointSSB,
- i,
- TS,
- KS,
- CS,
- SSA,
- SSB;
- // Ikh requires close value
- if (xVal.length <= period ||
- !isArray(yVal[0]) ||
- yVal[0].length !== 4) {
- return;
- }
- // Add timestamps at the beginning
- dateStart = xVal[0] - (period * closestPointRange);
- for (i = 0; i < period; i++) {
- xData.push(dateStart + i * closestPointRange);
- }
- for (i = 0; i < yValLen; i++) {
- // Tenkan Sen
- if (i >= periodTenkan) {
- slicedTSY = yVal.slice(i - periodTenkan, i);
- pointTS = highlowLevel(slicedTSY);
- TS = (pointTS.high + pointTS.low) / 2;
- }
- if (i >= period) {
- slicedKSY = yVal.slice(i - period, i);
- pointKS = highlowLevel(slicedKSY);
- KS = (pointKS.high + pointKS.low) / 2;
- SSA = (TS + KS) / 2;
- }
- if (i >= periodSenkouSpanB) {
- slicedSSBY = yVal.slice(i - periodSenkouSpanB, i);
- pointSSB = highlowLevel(slicedSSBY);
- SSB = (pointSSB.high + pointSSB.low) / 2;
- }
- CS = yVal[i][3];
- date = xVal[i];
- if (IKH[i] === UNDEFINED) {
- IKH[i] = [];
- }
- if (IKH[i + period] === UNDEFINED) {
- IKH[i + period] = [];
- }
- IKH[i + period][0] = TS;
- IKH[i + period][1] = KS;
- IKH[i + period][2] = UNDEFINED;
- IKH[i][2] = CS;
- if (i <= period) {
- IKH[i + period][3] = UNDEFINED;
- IKH[i + period][4] = UNDEFINED;
- }
- if (IKH[i + 2 * period] === UNDEFINED) {
- IKH[i + 2 * period] = [];
- }
- IKH[i + 2 * period][3] = SSA;
- IKH[i + 2 * period][4] = SSB;
- xData.push(date);
- }
- // Add timestamps for further points
- for (i = 1; i <= period; i++) {
- xData.push(date + i * closestPointRange);
- }
- return {
- values: IKH,
- xData: xData,
- yData: IKH
- };
- }
- });
- /**
- * A `IKH` series. If the [type](#series.ikh.type) option is not
- * specified, it is inherited from [chart.type](#chart.type).
- *
- * @extends series,plotOptions.ikh
- * @since 6.0.0
- * @product highstock
- * @excluding dataParser, dataURL
- * @requires stock/indicators/indicators
- * @requires stock/indicators/ichimoku-kinko-hyo
- * @apioption series.ikh
- */
- ''; // add doclet above to transpiled file
- });
- _registerModule(_modules, 'Stock/Indicators/KeltnerChannelsIndicator.js', [_modules['Core/Globals.js'], _modules['Core/Utilities.js'], _modules['Mixins/MultipleLines.js']], function (H, U, multipleLinesMixin) {
- /* *
- *
- * License: www.highcharts.com/license
- *
- * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
- *
- * */
- var correctFloat = U.correctFloat,
- merge = U.merge,
- seriesType = U.seriesType;
- var SMA = H.seriesTypes.sma,
- EMA = H.seriesTypes.ema,
- ATR = H.seriesTypes.atr;
- /**
- * The Keltner Channels series type.
- *
- * @private
- * @class
- * @name Highcharts.seriesTypes.keltnerchannels
- *
- * @augments Highcharts.Series
- */
- seriesType('keltnerchannels', 'sma',
- /**
- * Keltner Channels. This series requires the `linkedTo` option to be set
- * and should be loaded after the `stock/indicators/indicators.js`,
- * `stock/indicators/atr.js`, and `stock/ema/.js`.
- *
- * @sample {highstock} stock/indicators/keltner-channels
- * Keltner Channels
- *
- * @extends plotOptions.sma
- * @since 7.0.0
- * @product highstock
- * @excluding allAreas, colorAxis, compare, compareBase, joinBy, keys,
- * navigatorOptions, pointInterval, pointIntervalUnit,
- * pointPlacement, pointRange, pointStart,showInNavigator,
- * stacking
- * @requires stock/indicators/indicators
- * @requires stock/indicators/keltner-channels
- * @optionparent plotOptions.keltnerchannels
- */
- {
- params: {
- period: 20,
- /**
- * The ATR period.
- */
- periodATR: 10,
- /**
- * The ATR multiplier.
- */
- multiplierATR: 2
- },
- /**
- * Bottom line options.
- *
- */
- bottomLine: {
- /**
- * Styles for a bottom line.
- *
- */
- styles: {
- /**
- * Pixel width of the line.
- */
- lineWidth: 1,
- /**
- * Color of the line. If not set, it's inherited from
- * `plotOptions.keltnerchannels.color`
- */
- lineColor: void 0
- }
- },
- /**
- * Top line options.
- *
- * @extends plotOptions.keltnerchannels.bottomLine
- */
- topLine: {
- styles: {
- lineWidth: 1,
- lineColor: void 0
- }
- },
- tooltip: {
- pointFormat: '<span style="color:{point.color}">\u25CF</span><b> {series.name}</b><br/>Upper Channel: {point.top}<br/>EMA({series.options.params.period}): {point.middle}<br/>Lower Channel: {point.bottom}<br/>'
- },
- marker: {
- enabled: false
- },
- dataGrouping: {
- approximation: 'averages'
- },
- lineWidth: 1
- },
- /**
- * @lends Highcharts.Series#
- */
- merge(multipleLinesMixin, {
- pointArrayMap: ['top', 'middle', 'bottom'],
- pointValKey: 'middle',
- nameBase: 'Keltner Channels',
- nameComponents: ['period', 'periodATR', 'multiplierATR'],
- linesApiNames: ['topLine', 'bottomLine'],
- requiredIndicators: ['ema', 'atr'],
- init: function () {
- SMA.prototype.init.apply(this, arguments);
- // Set default color for lines:
- this.options = merge({
- topLine: {
- styles: {
- lineColor: this.color
- }
- },
- bottomLine: {
- styles: {
- lineColor: this.color
- }
- }
- }, this.options);
- },
- getValues: function (series, params) {
- var period = params.period,
- periodATR = params.periodATR,
- multiplierATR = params.multiplierATR,
- index = params.index,
- yVal = series.yData,
- yValLen = yVal ? yVal.length : 0,
- // Keltner Channels array structure:
- // 0-date, 1-top line, 2-middle line, 3-bottom line
- KC = [],
- // middle line, top line and bottom lineI
- ML,
- TL,
- BL,
- date,
- seriesEMA = EMA.prototype.getValues(series, {
- period: period,
- index: index
- }),
- seriesATR = ATR.prototype.getValues(series, {
- period: periodATR
- }),
- pointEMA,
- pointATR,
- xData = [],
- yData = [],
- i;
- if (yValLen < period) {
- return;
- }
- for (i = period; i <= yValLen; i++) {
- pointEMA = seriesEMA.values[i - period];
- pointATR = seriesATR.values[i - periodATR];
- date = pointEMA[0];
- TL = correctFloat(pointEMA[1] + (multiplierATR * pointATR[1]));
- BL = correctFloat(pointEMA[1] - (multiplierATR * pointATR[1]));
- ML = pointEMA[1];
- KC.push([date, TL, ML, BL]);
- xData.push(date);
- yData.push([TL, ML, BL]);
- }
- return {
- values: KC,
- xData: xData,
- yData: yData
- };
- }
- }));
- /**
- * A Keltner Channels indicator. If the [type](#series.keltnerchannels.type)
- * option is not specified, it is inherited from[chart.type](#chart.type).
- *
- * @extends series,plotOptions.keltnerchannels
- * @since 7.0.0
- * @product highstock
- * @excluding allAreas, colorAxis, compare, compareBase, dataParser, dataURL,
- * joinBy, keys, navigatorOptions, pointInterval,
- * pointIntervalUnit, pointPlacement, pointRange, pointStart,
- * stacking, showInNavigator
- * @requires stock/indicators/indicators
- * @requires stock/indicators/keltner-channels
- * @apioption series.keltnerchannels
- */
- ''; // to include the above in the js output
- });
- _registerModule(_modules, 'Stock/Indicators/MACDIndicator.js', [_modules['Core/Globals.js'], _modules['Core/Utilities.js']], function (H, U) {
- /* *
- *
- * License: www.highcharts.com/license
- *
- * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
- *
- * */
- var correctFloat = U.correctFloat,
- defined = U.defined,
- merge = U.merge,
- seriesType = U.seriesType;
- var noop = H.noop,
- SMA = H.seriesTypes.sma,
- EMA = H.seriesTypes.ema;
- /**
- * The MACD series type.
- *
- * @private
- * @class
- * @name Highcharts.seriesTypes.macd
- *
- * @augments Highcharts.Series
- */
- seriesType('macd', 'sma',
- /**
- * Moving Average Convergence Divergence (MACD). This series requires
- * `linkedTo` option to be set and should be loaded after the
- * `stock/indicators/indicators.js` and `stock/indicators/ema.js`.
- *
- * @sample stock/indicators/macd
- * MACD indicator
- *
- * @extends plotOptions.sma
- * @since 6.0.0
- * @product highstock
- * @requires stock/indicators/indicators
- * @requires stock/indicators/macd
- * @optionparent plotOptions.macd
- */
- {
- params: {
- /**
- * The short period for indicator calculations.
- */
- shortPeriod: 12,
- /**
- * The long period for indicator calculations.
- */
- longPeriod: 26,
- /**
- * The base period for signal calculations.
- */
- signalPeriod: 9,
- period: 26
- },
- /**
- * The styles for signal line
- */
- signalLine: {
- /**
- * @sample stock/indicators/macd-zones
- * Zones in MACD
- *
- * @extends plotOptions.macd.zones
- */
- zones: [],
- styles: {
- /**
- * Pixel width of the line.
- */
- lineWidth: 1,
- /**
- * Color of the line.
- *
- * @type {Highcharts.ColorString}
- */
- lineColor: void 0
- }
- },
- /**
- * The styles for macd line
- */
- macdLine: {
- /**
- * @sample stock/indicators/macd-zones
- * Zones in MACD
- *
- * @extends plotOptions.macd.zones
- */
- zones: [],
- styles: {
- /**
- * Pixel width of the line.
- */
- lineWidth: 1,
- /**
- * Color of the line.
- *
- * @type {Highcharts.ColorString}
- */
- lineColor: void 0
- }
- },
- threshold: 0,
- groupPadding: 0.1,
- pointPadding: 0.1,
- crisp: false,
- states: {
- hover: {
- halo: {
- size: 0
- }
- }
- },
- tooltip: {
- pointFormat: '<span style="color:{point.color}">\u25CF</span> <b> {series.name}</b><br/>' +
- 'Value: {point.MACD}<br/>' +
- 'Signal: {point.signal}<br/>' +
- 'Histogram: {point.y}<br/>'
- },
- dataGrouping: {
- approximation: 'averages'
- },
- minPointLength: 0
- },
- /**
- * @lends Highcharts.Series#
- */
- {
- nameComponents: ['longPeriod', 'shortPeriod', 'signalPeriod'],
- requiredIndicators: ['ema'],
- // "y" value is treated as Histogram data
- pointArrayMap: ['y', 'signal', 'MACD'],
- parallelArrays: ['x', 'y', 'signal', 'MACD'],
- pointValKey: 'y',
- // Columns support:
- markerAttribs: noop,
- getColumnMetrics: H.seriesTypes.column.prototype.getColumnMetrics,
- crispCol: H.seriesTypes.column.prototype.crispCol,
- // Colors and lines:
- init: function () {
- SMA.prototype.init.apply(this, arguments);
- // Check whether series is initialized. It may be not initialized,
- // when any of required indicators is missing.
- if (this.options) {
- // Set default color for a signal line and the histogram:
- this.options = merge({
- signalLine: {
- styles: {
- lineColor: this.color
- }
- },
- macdLine: {
- styles: {
- color: this.color
- }
- }
- }, this.options);
- // Zones have indexes automatically calculated, we need to
- // translate them to support multiple lines within one indicator
- this.macdZones = {
- zones: this.options.macdLine.zones,
- startIndex: 0
- };
- this.signalZones = {
- zones: this.macdZones.zones.concat(this.options.signalLine.zones),
- startIndex: this.macdZones.zones.length
- };
- this.resetZones = true;
- }
- },
- toYData: function (point) {
- return [point.y, point.signal, point.MACD];
- },
- translate: function () {
- var indicator = this, plotNames = ['plotSignal', 'plotMACD'];
- H.seriesTypes.column.prototype.translate.apply(indicator);
- indicator.points.forEach(function (point) {
- [point.signal, point.MACD].forEach(function (value, i) {
- if (value !== null) {
- point[plotNames[i]] =
- indicator.yAxis.toPixels(value, true);
- }
- });
- });
- },
- destroy: function () {
- // this.graph is null due to removing two times the same SVG element
- this.graph = null;
- this.graphmacd = this.graphmacd && this.graphmacd.destroy();
- this.graphsignal = this.graphsignal && this.graphsignal.destroy();
- SMA.prototype.destroy.apply(this, arguments);
- },
- drawPoints: H.seriesTypes.column.prototype.drawPoints,
- drawGraph: function () {
- var indicator = this,
- mainLinePoints = indicator.points,
- pointsLength = mainLinePoints.length,
- mainLineOptions = indicator.options,
- histogramZones = indicator.zones,
- gappedExtend = {
- options: {
- gapSize: mainLineOptions.gapSize
- }
- },
- otherSignals = [[],
- []],
- point;
- // Generate points for top and bottom lines:
- while (pointsLength--) {
- point = mainLinePoints[pointsLength];
- if (defined(point.plotMACD)) {
- otherSignals[0].push({
- plotX: point.plotX,
- plotY: point.plotMACD,
- isNull: !defined(point.plotMACD)
- });
- }
- if (defined(point.plotSignal)) {
- otherSignals[1].push({
- plotX: point.plotX,
- plotY: point.plotSignal,
- isNull: !defined(point.plotMACD)
- });
- }
- }
- // Modify options and generate smoothing line:
- ['macd', 'signal'].forEach(function (lineName, i) {
- indicator.points = otherSignals[i];
- indicator.options = merge(mainLineOptions[lineName + 'Line'].styles, gappedExtend);
- indicator.graph = indicator['graph' + lineName];
- // Zones extension:
- indicator.currentLineZone = lineName + 'Zones';
- indicator.zones =
- indicator[indicator.currentLineZone].zones;
- SMA.prototype.drawGraph.call(indicator);
- indicator['graph' + lineName] = indicator.graph;
- });
- // Restore options:
- indicator.points = mainLinePoints;
- indicator.options = mainLineOptions;
- indicator.zones = histogramZones;
- indicator.currentLineZone = null;
- // indicator.graph = null;
- },
- getZonesGraphs: function (props) {
- var allZones = SMA.prototype.getZonesGraphs.call(this,
- props),
- currentZones = allZones;
- if (this.currentLineZone) {
- currentZones = allZones.splice(this[this.currentLineZone].startIndex + 1);
- if (!currentZones.length) {
- // Line has no zones, return basic graph "zone"
- currentZones = [props[0]];
- }
- else {
- // Add back basic prop:
- currentZones.splice(0, 0, props[0]);
- }
- }
- return currentZones;
- },
- applyZones: function () {
- // Histogram zones are handled by drawPoints method
- // Here we need to apply zones for all lines
- var histogramZones = this.zones;
- // signalZones.zones contains all zones:
- this.zones = this.signalZones.zones;
- SMA.prototype.applyZones.call(this);
- // applyZones hides only main series.graph, hide macd line manually
- if (this.graphmacd && this.options.macdLine.zones.length) {
- this.graphmacd.hide();
- }
- this.zones = histogramZones;
- },
- getValues: function (series, params) {
- var j = 0,
- MACD = [],
- xMACD = [],
- yMACD = [],
- signalLine = [],
- shortEMA,
- longEMA,
- i;
- if (series.xData.length <
- params.longPeriod + params.signalPeriod) {
- return;
- }
- // Calculating the short and long EMA used when calculating the MACD
- shortEMA = EMA.prototype.getValues(series, {
- period: params.shortPeriod
- });
- longEMA = EMA.prototype.getValues(series, {
- period: params.longPeriod
- });
- shortEMA = shortEMA.values;
- longEMA = longEMA.values;
- // Subtract each Y value from the EMA's and create the new dataset
- // (MACD)
- for (i = 1; i <= shortEMA.length; i++) {
- if (defined(longEMA[i - 1]) &&
- defined(longEMA[i - 1][1]) &&
- defined(shortEMA[i + params.shortPeriod + 1]) &&
- defined(shortEMA[i + params.shortPeriod + 1][0])) {
- MACD.push([
- shortEMA[i + params.shortPeriod + 1][0],
- 0,
- null,
- shortEMA[i + params.shortPeriod + 1][1] -
- longEMA[i - 1][1]
- ]);
- }
- }
- // Set the Y and X data of the MACD. This is used in calculating the
- // signal line.
- for (i = 0; i < MACD.length; i++) {
- xMACD.push(MACD[i][0]);
- yMACD.push([0, null, MACD[i][3]]);
- }
- // Setting the signalline (Signal Line: X-day EMA of MACD line).
- signalLine = EMA.prototype.getValues({
- xData: xMACD,
- yData: yMACD
- }, {
- period: params.signalPeriod,
- index: 2
- });
- signalLine = signalLine.values;
- // Setting the MACD Histogram. In comparison to the loop with pure
- // MACD this loop uses MACD x value not xData.
- for (i = 0; i < MACD.length; i++) {
- // detect the first point
- if (MACD[i][0] >= signalLine[0][0]) {
- MACD[i][2] = signalLine[j][1];
- yMACD[i] = [0, signalLine[j][1], MACD[i][3]];
- if (MACD[i][3] === null) {
- MACD[i][1] = 0;
- yMACD[i][0] = 0;
- }
- else {
- MACD[i][1] = correctFloat(MACD[i][3] -
- signalLine[j][1]);
- yMACD[i][0] = correctFloat(MACD[i][3] -
- signalLine[j][1]);
- }
- j++;
- }
- }
- return {
- values: MACD,
- xData: xMACD,
- yData: yMACD
- };
- }
- });
- /**
- * A `MACD` series. If the [type](#series.macd.type) option is not
- * specified, it is inherited from [chart.type](#chart.type).
- *
- * @extends series,plotOptions.macd
- * @since 6.0.0
- * @product highstock
- * @excluding dataParser, dataURL
- * @requires stock/indicators/indicators
- * @requires stock/indicators/macd
- * @apioption series.macd
- */
- ''; // to include the above in the js output
- });
- _registerModule(_modules, 'Stock/Indicators/MFIIndicator.js', [_modules['Core/Utilities.js']], function (U) {
- /* *
- *
- * Money Flow Index indicator for Highstock
- *
- * (c) 2010-2020 Grzegorz Blachliński
- *
- * License: www.highcharts.com/license
- *
- * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
- *
- * */
- var error = U.error,
- isArray = U.isArray,
- seriesType = U.seriesType;
- /* eslint-disable require-jsdoc */
- // Utils:
- function sumArray(array) {
- return array.reduce(function (prev, cur) {
- return prev + cur;
- });
- }
- function toFixed(a, n) {
- return parseFloat(a.toFixed(n));
- }
- function calculateTypicalPrice(point) {
- return (point[1] + point[2] + point[3]) / 3;
- }
- function calculateRawMoneyFlow(typicalPrice, volume) {
- return typicalPrice * volume;
- }
- /* eslint-enable require-jsdoc */
- /**
- * The MFI series type.
- *
- * @private
- * @class
- * @name Highcharts.seriesTypes.mfi
- *
- * @augments Highcharts.Series
- */
- seriesType('mfi', 'sma',
- /**
- * Money Flow Index. This series requires `linkedTo` option to be set and
- * should be loaded after the `stock/indicators/indicators.js` file.
- *
- * @sample stock/indicators/mfi
- * Money Flow Index Indicator
- *
- * @extends plotOptions.sma
- * @since 6.0.0
- * @product highstock
- * @requires stock/indicators/indicators
- * @requires stock/indicators/mfi
- * @optionparent plotOptions.mfi
- */
- {
- /**
- * @excluding index
- */
- params: {
- period: 14,
- /**
- * The id of volume series which is mandatory.
- * For example using OHLC data, volumeSeriesID='volume' means
- * the indicator will be calculated using OHLC and volume values.
- */
- volumeSeriesID: 'volume',
- /**
- * Number of maximum decimals that are used in MFI calculations.
- */
- decimals: 4
- }
- },
- /**
- * @lends Highcharts.Series#
- */
- {
- nameBase: 'Money Flow Index',
- getValues: function (series, params) {
- var period = params.period,
- xVal = series.xData,
- yVal = series.yData,
- yValLen = yVal ? yVal.length : 0,
- decimals = params.decimals,
- // MFI starts calculations from the second point
- // Cause we need to calculate change between two points
- range = 1,
- volumeSeries = series.chart.get(params.volumeSeriesID),
- yValVolume = (volumeSeries && volumeSeries.yData),
- MFI = [],
- isUp = false,
- xData = [],
- yData = [],
- positiveMoneyFlow = [],
- negativeMoneyFlow = [],
- newTypicalPrice,
- oldTypicalPrice,
- rawMoneyFlow,
- negativeMoneyFlowSum,
- positiveMoneyFlowSum,
- moneyFlowRatio,
- MFIPoint,
- i;
- if (!volumeSeries) {
- error('Series ' +
- params.volumeSeriesID +
- ' not found! Check `volumeSeriesID`.', true, series.chart);
- return;
- }
- // MFI requires high low and close values
- if ((xVal.length <= period) || !isArray(yVal[0]) ||
- yVal[0].length !== 4 ||
- !yValVolume) {
- return;
- }
- // Calculate first typical price
- newTypicalPrice = calculateTypicalPrice(yVal[range]);
- // Accumulate first N-points
- while (range < period + 1) {
- // Calculate if up or down
- oldTypicalPrice = newTypicalPrice;
- newTypicalPrice = calculateTypicalPrice(yVal[range]);
- isUp = newTypicalPrice >= oldTypicalPrice;
- // Calculate raw money flow
- rawMoneyFlow = calculateRawMoneyFlow(newTypicalPrice, yValVolume[range]);
- // Add to array
- positiveMoneyFlow.push(isUp ? rawMoneyFlow : 0);
- negativeMoneyFlow.push(isUp ? 0 : rawMoneyFlow);
- range++;
- }
- for (i = range - 1; i < yValLen; i++) {
- if (i > range - 1) {
- // Remove first point from array
- positiveMoneyFlow.shift();
- negativeMoneyFlow.shift();
- // Calculate if up or down
- oldTypicalPrice = newTypicalPrice;
- newTypicalPrice = calculateTypicalPrice(yVal[i]);
- isUp = newTypicalPrice > oldTypicalPrice;
- // Calculate raw money flow
- rawMoneyFlow = calculateRawMoneyFlow(newTypicalPrice, yValVolume[i]);
- // Add to array
- positiveMoneyFlow.push(isUp ? rawMoneyFlow : 0);
- negativeMoneyFlow.push(isUp ? 0 : rawMoneyFlow);
- }
- // Calculate sum of negative and positive money flow:
- negativeMoneyFlowSum = sumArray(negativeMoneyFlow);
- positiveMoneyFlowSum = sumArray(positiveMoneyFlow);
- moneyFlowRatio = positiveMoneyFlowSum / negativeMoneyFlowSum;
- MFIPoint = toFixed(100 - (100 / (1 + moneyFlowRatio)), decimals);
- MFI.push([xVal[i], MFIPoint]);
- xData.push(xVal[i]);
- yData.push(MFIPoint);
- }
- return {
- values: MFI,
- xData: xData,
- yData: yData
- };
- }
- });
- /**
- * A `MFI` series. If the [type](#series.mfi.type) option is not specified, it
- * is inherited from [chart.type](#chart.type).
- *
- * @extends series,plotOptions.mfi
- * @since 6.0.0
- * @excluding dataParser, dataURL
- * @product highstock
- * @requires stock/indicators/indicators
- * @requires stock/indicators/mfi
- * @apioption series.mfi
- */
- ''; // to include the above in the js output
- });
- _registerModule(_modules, 'Stock/Indicators/MomentumIndicator.js', [_modules['Core/Utilities.js']], function (U) {
- /* *
- *
- * License: www.highcharts.com/license
- *
- * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
- *
- * */
- var isArray = U.isArray,
- seriesType = U.seriesType;
- /* eslint-disable require-jsdoc */
- function populateAverage(points, xVal, yVal, i, period) {
- var mmY = yVal[i - 1][3] - yVal[i - period - 1][3],
- mmX = xVal[i - 1];
- points.shift(); // remove point until range < period
- return [mmX, mmY];
- }
- /* eslint-enable require-jsdoc */
- /**
- * The Momentum series type.
- *
- * @private
- * @class
- * @name Highcharts.seriesTypes.momentum
- *
- * @augments Highcharts.Series
- */
- seriesType('momentum', 'sma',
- /**
- * Momentum. This series requires `linkedTo` option to be set.
- *
- * @sample stock/indicators/momentum
- * Momentum indicator
- *
- * @extends plotOptions.sma
- * @since 6.0.0
- * @product highstock
- * @requires stock/indicators/indicators
- * @requires stock/indicators/momentum
- * @optionparent plotOptions.momentum
- */
- {
- params: {
- period: 14
- }
- },
- /**
- * @lends Highcharts.Series#
- */
- {
- nameBase: 'Momentum',
- getValues: function (series, params) {
- var period = params.period,
- xVal = series.xData,
- yVal = series.yData,
- yValLen = yVal ? yVal.length : 0,
- xValue = xVal[0],
- yValue = yVal[0],
- MM = [],
- xData = [],
- yData = [],
- index,
- i,
- points,
- MMPoint;
- if (xVal.length <= period) {
- return;
- }
- // Switch index for OHLC / Candlestick / Arearange
- if (isArray(yVal[0])) {
- yValue = yVal[0][3];
- }
- else {
- return;
- }
- // Starting point
- points = [
- [xValue, yValue]
- ];
- // Calculate value one-by-one for each period in visible data
- for (i = (period + 1); i < yValLen; i++) {
- MMPoint = populateAverage(points, xVal, yVal, i, period, index);
- MM.push(MMPoint);
- xData.push(MMPoint[0]);
- yData.push(MMPoint[1]);
- }
- MMPoint = populateAverage(points, xVal, yVal, i, period, index);
- MM.push(MMPoint);
- xData.push(MMPoint[0]);
- yData.push(MMPoint[1]);
- return {
- values: MM,
- xData: xData,
- yData: yData
- };
- }
- });
- /**
- * A `Momentum` series. If the [type](#series.momentum.type) option is not
- * specified, it is inherited from [chart.type](#chart.type).
- *
- * @extends series,plotOptions.momentum
- * @since 6.0.0
- * @excluding dataParser, dataURL
- * @product highstock
- * @requires stock/indicators/indicators
- * @requires stock/indicators/momentum
- * @apioption series.momentum
- */
- ''; // to include the above in the js output
- });
- _registerModule(_modules, 'Stock/Indicators/NATRIndicator.js', [_modules['Core/Globals.js'], _modules['Core/Utilities.js']], function (H, U) {
- /* *
- *
- * License: www.highcharts.com/license
- *
- * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
- *
- * */
- var seriesType = U.seriesType;
- var ATR = H.seriesTypes.atr;
- /**
- * The NATR series type.
- *
- * @private
- * @class
- * @name Highcharts.seriesTypes.natr
- *
- * @augments Highcharts.Series
- */
- seriesType('natr', 'sma',
- /**
- * Normalized average true range indicator (NATR). This series requires
- * `linkedTo` option to be set and should be loaded after the
- * `stock/indicators/indicators.js` and `stock/indicators/atr.js`.
- *
- * @sample {highstock} stock/indicators/natr
- * NATR indicator
- *
- * @extends plotOptions.atr
- * @since 7.0.0
- * @product highstock
- * @requires stock/indicators/indicators
- * @requires stock/indicators/natr
- * @optionparent plotOptions.natr
- */
- {
- tooltip: {
- valueSuffix: '%'
- }
- },
- /**
- * @lends Highcharts.Series#
- */
- {
- requiredIndicators: ['atr'],
- getValues: function (series, params) {
- var atrData = (ATR.prototype.getValues.apply(this,
- arguments)),
- atrLength = atrData.values.length,
- period = params.period - 1,
- yVal = series.yData,
- i = 0;
- if (!atrData) {
- return;
- }
- for (; i < atrLength; i++) {
- atrData.yData[i] = (atrData.values[i][1] / yVal[period][3] * 100);
- atrData.values[i][1] = atrData.yData[i];
- period++;
- }
- return atrData;
- }
- });
- /**
- * A `NATR` series. If the [type](#series.natr.type) option is not specified, it
- * is inherited from [chart.type](#chart.type).
- *
- * @extends series,plotOptions.natr
- * @since 7.0.0
- * @product highstock
- * @excluding dataParser, dataURL
- * @requires stock/indicators/indicators
- * @requires stock/indicators/natr
- * @apioption series.natr
- */
- ''; // to include the above in the js output'
- });
- _registerModule(_modules, 'Stock/Indicators/PivotPointsIndicator.js', [_modules['Core/Globals.js'], _modules['Core/Utilities.js']], function (H, U) {
- /* *
- *
- * License: www.highcharts.com/license
- *
- * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
- *
- * */
- var defined = U.defined,
- isArray = U.isArray,
- seriesType = U.seriesType;
- var SMA = H.seriesTypes.sma;
- /* eslint-disable valid-jsdoc */
- /**
- * @private
- */
- function destroyExtraLabels(point, functionName) {
- var props = point.series.pointArrayMap,
- prop,
- i = props.length;
- SMA.prototype.pointClass.prototype[functionName].call(point);
- while (i--) {
- prop = 'dataLabel' + props[i];
- // S4 dataLabel could be removed by parent method:
- if (point[prop] && point[prop].element) {
- point[prop].destroy();
- }
- point[prop] = null;
- }
- }
- /* eslint-enable valid-jsdoc */
- /**
- * The Pivot Points series type.
- *
- * @private
- * @class
- * @name Highcharts.seriesTypes.pivotpoints
- *
- * @augments Highcharts.Series
- */
- seriesType('pivotpoints', 'sma',
- /**
- * Pivot points indicator. This series requires the `linkedTo` option to be
- * set and should be loaded after `stock/indicators/indicators.js` file.
- *
- * @sample stock/indicators/pivot-points
- * Pivot points
- *
- * @extends plotOptions.sma
- * @since 6.0.0
- * @product highstock
- * @requires stock/indicators/indicators
- * @requires stock/indicators/pivotpoints
- * @optionparent plotOptions.pivotpoints
- */
- {
- /**
- * @excluding index
- */
- params: {
- period: 28,
- /**
- * Algorithm used to calculate ressistance and support lines based
- * on pivot points. Implemented algorithms: `'standard'`,
- * `'fibonacci'` and `'camarilla'`
- */
- algorithm: 'standard'
- },
- marker: {
- enabled: false
- },
- enableMouseTracking: false,
- dataLabels: {
- enabled: true,
- format: '{point.pivotLine}'
- },
- dataGrouping: {
- approximation: 'averages'
- }
- },
- /**
- * @lends Highcharts.Series#
- */
- {
- nameBase: 'Pivot Points',
- pointArrayMap: ['R4', 'R3', 'R2', 'R1', 'P', 'S1', 'S2', 'S3', 'S4'],
- pointValKey: 'P',
- toYData: function (point) {
- return [point.P]; // The rest should not affect extremes
- },
- translate: function () {
- var indicator = this;
- SMA.prototype.translate.apply(indicator);
- indicator.points.forEach(function (point) {
- indicator.pointArrayMap.forEach(function (value) {
- if (defined(point[value])) {
- point['plot' + value] = (indicator.yAxis.toPixels(point[value], true));
- }
- });
- });
- // Pivot points are rendered as horizontal lines
- // And last point start not from the next one (as it's the last one)
- // But from the approximated last position in a given range
- indicator.plotEndPoint = indicator.xAxis.toPixels(indicator.endPoint, true);
- },
- getGraphPath: function (points) {
- var indicator = this,
- pointsLength = points.length,
- allPivotPoints = ([[],
- [],
- [],
- [],
- [],
- [],
- [],
- [],
- []]),
- path = [],
- endPoint = indicator.plotEndPoint,
- pointArrayMapLength = indicator.pointArrayMap.length,
- position,
- point,
- i;
- while (pointsLength--) {
- point = points[pointsLength];
- for (i = 0; i < pointArrayMapLength; i++) {
- position = indicator.pointArrayMap[i];
- if (defined(point[position])) {
- allPivotPoints[i].push({
- // Start left:
- plotX: point.plotX,
- plotY: point['plot' + position],
- isNull: false
- }, {
- // Go to right:
- plotX: endPoint,
- plotY: point['plot' + position],
- isNull: false
- }, {
- // And add null points in path to generate breaks:
- plotX: endPoint,
- plotY: null,
- isNull: true
- });
- }
- }
- endPoint = point.plotX;
- }
- allPivotPoints.forEach(function (pivotPoints) {
- path = path.concat(SMA.prototype.getGraphPath.call(indicator, pivotPoints));
- });
- return path;
- },
- // TODO: Rewrite this logic to use multiple datalabels
- drawDataLabels: function () {
- var indicator = this,
- pointMapping = indicator.pointArrayMap,
- currentLabel,
- pointsLength,
- point,
- i;
- if (indicator.options.dataLabels.enabled) {
- pointsLength = indicator.points.length;
- // For every Ressitance/Support group we need to render labels.
- // Add one more item, which will just store dataLabels from
- // previous iteration
- pointMapping.concat([false]).forEach(function (position, k) {
- i = pointsLength;
- while (i--) {
- point = indicator.points[i];
- if (!position) {
- // Store S4 dataLabel too:
- point['dataLabel' + pointMapping[k - 1]] =
- point.dataLabel;
- }
- else {
- point.y = point[position];
- point.pivotLine = position;
- point.plotY = point['plot' + position];
- currentLabel = point['dataLabel' + position];
- // Store previous label
- if (k) {
- point['dataLabel' + pointMapping[k - 1]] = point.dataLabel;
- }
- if (!point.dataLabels) {
- point.dataLabels = [];
- }
- point.dataLabels[0] = point.dataLabel =
- currentLabel =
- currentLabel && currentLabel.element ?
- currentLabel :
- null;
- }
- }
- SMA.prototype.drawDataLabels.apply(indicator, arguments);
- });
- }
- },
- getValues: function (series, params) {
- var period = params.period,
- xVal = series.xData,
- yVal = series.yData,
- yValLen = yVal ? yVal.length : 0,
- placement = this[params.algorithm + 'Placement'],
- // 0- from, 1- to, 2- R1, 3- R2, 4- pivot, 5- S1 etc.
- PP = [],
- endTimestamp,
- xData = [],
- yData = [],
- slicedXLen,
- slicedX,
- slicedY,
- lastPP,
- pivot,
- avg,
- i;
- // Pivot Points requires high, low and close values
- if (xVal.length < period ||
- !isArray(yVal[0]) ||
- yVal[0].length !== 4) {
- return;
- }
- for (i = period + 1; i <= yValLen + period; i += period) {
- slicedX = xVal.slice(i - period - 1, i);
- slicedY = yVal.slice(i - period - 1, i);
- slicedXLen = slicedX.length;
- endTimestamp = slicedX[slicedXLen - 1];
- pivot = this.getPivotAndHLC(slicedY);
- avg = placement(pivot);
- lastPP = PP.push([endTimestamp]
- .concat(avg));
- xData.push(endTimestamp);
- yData.push(PP[lastPP - 1].slice(1));
- }
- // We don't know exact position in ordinal axis
- // So we use simple logic:
- // Get first point in last range, calculate visible average range
- // and multiply by period
- this.endPoint = slicedX[0] + ((endTimestamp - slicedX[0]) /
- slicedXLen) * period;
- return {
- values: PP,
- xData: xData,
- yData: yData
- };
- },
- getPivotAndHLC: function (values) {
- var high = -Infinity,
- low = Infinity,
- close = values[values.length - 1][3],
- pivot;
- values.forEach(function (p) {
- high = Math.max(high, p[1]);
- low = Math.min(low, p[2]);
- });
- pivot = (high + low + close) / 3;
- return [pivot, high, low, close];
- },
- standardPlacement: function (values) {
- var diff = values[1] - values[2],
- avg = [
- null,
- null,
- values[0] + diff,
- values[0] * 2 - values[2],
- values[0],
- values[0] * 2 - values[1],
- values[0] - diff,
- null,
- null
- ];
- return avg;
- },
- camarillaPlacement: function (values) {
- var diff = values[1] - values[2],
- avg = [
- values[3] + diff * 1.5,
- values[3] + diff * 1.25,
- values[3] + diff * 1.1666,
- values[3] + diff * 1.0833,
- values[0],
- values[3] - diff * 1.0833,
- values[3] - diff * 1.1666,
- values[3] - diff * 1.25,
- values[3] - diff * 1.5
- ];
- return avg;
- },
- fibonacciPlacement: function (values) {
- var diff = values[1] - values[2],
- avg = [
- null,
- values[0] + diff,
- values[0] + diff * 0.618,
- values[0] + diff * 0.382,
- values[0],
- values[0] - diff * 0.382,
- values[0] - diff * 0.618,
- values[0] - diff,
- null
- ];
- return avg;
- }
- },
- /**
- * @lends Highcharts.Point#
- */
- {
- // Destroy labels:
- // This method is called when cropping data:
- destroyElements: function () {
- destroyExtraLabels(this, 'destroyElements');
- },
- // This method is called when removing points, e.g. series.update()
- destroy: function () {
- destroyExtraLabels(this, 'destroyElements');
- }
- });
- /**
- * A pivot points indicator. If the [type](#series.pivotpoints.type) option is
- * not specified, it is inherited from [chart.type](#chart.type).
- *
- * @extends series,plotOptions.pivotpoints
- * @since 6.0.0
- * @product highstock
- * @excluding dataParser, dataURL
- * @requires stock/indicators/indicators
- * @requires stock/indicators/pivotpoints
- * @apioption series.pivotpoints
- */
- ''; // to include the above in the js output'
- });
- _registerModule(_modules, 'Stock/Indicators/PPOIndicator.js', [_modules['Core/Globals.js'], _modules['Core/Utilities.js'], _modules['Mixins/IndicatorRequired.js']], function (H, U, requiredIndicator) {
- /* *
- *
- * License: www.highcharts.com/license
- *
- * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
- *
- * */
- var correctFloat = U.correctFloat,
- error = U.error,
- seriesType = U.seriesType;
- var EMA = H.seriesTypes.ema;
- /**
- * The PPO series type.
- *
- * @private
- * @class
- * @name Highcharts.seriesTypes.ppo
- *
- * @augments Highcharts.Series
- */
- seriesType('ppo', 'ema',
- /**
- * Percentage Price Oscillator. This series requires the
- * `linkedTo` option to be set and should be loaded after the
- * `stock/indicators/indicators.js` and `stock/indicators/ema.js`.
- *
- * @sample {highstock} stock/indicators/ppo
- * Percentage Price Oscillator
- *
- * @extends plotOptions.ema
- * @since 7.0.0
- * @product highstock
- * @excluding allAreas, colorAxis, joinBy, keys, navigatorOptions,
- * pointInterval, pointIntervalUnit, pointPlacement,
- * pointRange, pointStart, showInNavigator, stacking
- * @requires stock/indicators/indicators
- * @requires stock/indicators/ema
- * @requires stock/indicators/ppo
- * @optionparent plotOptions.ppo
- */
- {
- /**
- * Paramters used in calculation of Percentage Price Oscillator series
- * points.
- *
- * @excluding period
- */
- params: {
- /**
- * Periods for Percentage Price Oscillator calculations.
- *
- * @type {Array<number>}
- * @default [12, 26]
- */
- periods: [12, 26]
- }
- },
- /**
- * @lends Highcharts.Series.prototype
- */
- {
- nameBase: 'PPO',
- nameComponents: ['periods'],
- init: function () {
- var args = arguments,
- ctx = this;
- requiredIndicator.isParentLoaded(EMA, 'ema', ctx.type, function (indicator) {
- indicator.prototype.init.apply(ctx, args);
- return;
- });
- },
- getValues: function (series, params) {
- var periods = params.periods,
- index = params.index,
- // 0- date, 1- Percentage Price Oscillator
- PPO = [],
- xData = [],
- yData = [],
- periodsOffset,
- // Shorter Period EMA
- SPE,
- // Longer Period EMA
- LPE,
- oscillator,
- i;
- // Check if periods are correct
- if (periods.length !== 2 || periods[1] <= periods[0]) {
- error('Error: "PPO requires two periods. Notice, first period ' +
- 'should be lower than the second one."');
- return;
- }
- SPE = EMA.prototype.getValues.call(this, series, {
- index: index,
- period: periods[0]
- });
- LPE = EMA.prototype.getValues.call(this, series, {
- index: index,
- period: periods[1]
- });
- // Check if ema is calculated properly, if not skip
- if (!SPE || !LPE) {
- return;
- }
- periodsOffset = periods[1] - periods[0];
- for (i = 0; i < LPE.yData.length; i++) {
- oscillator = correctFloat((SPE.yData[i + periodsOffset] -
- LPE.yData[i]) /
- LPE.yData[i] *
- 100);
- PPO.push([LPE.xData[i], oscillator]);
- xData.push(LPE.xData[i]);
- yData.push(oscillator);
- }
- return {
- values: PPO,
- xData: xData,
- yData: yData
- };
- }
- });
- /**
- * A `Percentage Price Oscillator` series. If the [type](#series.ppo.type)
- * option is not specified, it is inherited from [chart.type](#chart.type).
- *
- * @extends series,plotOptions.ppo
- * @since 7.0.0
- * @product highstock
- * @excluding allAreas, colorAxis, dataParser, dataURL, joinBy, keys,
- * navigatorOptions, pointInterval, pointIntervalUnit,
- * pointPlacement, pointRange, pointStart, showInNavigator, stacking
- * @requires stock/indicators/indicators
- * @requires stock/indicators/ema
- * @requires stock/indicators/ppo
- * @apioption series.ppo
- */
- ''; // to include the above in the js output
- });
- _registerModule(_modules, 'Mixins/ReduceArray.js', [], function () {
- /**
- *
- * (c) 2010-2020 Pawel Fus & Daniel Studencki
- *
- * License: www.highcharts.com/license
- *
- * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
- *
- * */
- var reduceArrayMixin = {
- /**
- * Get min value of array filled by OHLC data.
- * @private
- * @param {Array<*>} arr Array of OHLC points (arrays).
- * @param {string} index Index of "low" value in point array.
- * @return {number} Returns min value.
- */
- minInArray: function (arr,
- index) {
- return arr.reduce(function (min,
- target) {
- return Math.min(min,
- target[index]);
- }, Number.MAX_VALUE);
- },
- /**
- * Get max value of array filled by OHLC data.
- * @private
- * @param {Array<*>} arr Array of OHLC points (arrays).
- * @param {string} index Index of "high" value in point array.
- * @return {number} Returns max value.
- */
- maxInArray: function (arr, index) {
- return arr.reduce(function (max, target) {
- return Math.max(max, target[index]);
- }, -Number.MAX_VALUE);
- },
- /**
- * Get extremes of array filled by OHLC data.
- * @private
- * @param {Array<*>} arr Array of OHLC points (arrays).
- * @param {string} minIndex Index of "low" value in point array.
- * @param {string} maxIndex Index of "high" value in point array.
- * @return {Array<number,number>} Returns array with min and max value.
- */
- getArrayExtremes: function (arr, minIndex, maxIndex) {
- return arr.reduce(function (prev, target) {
- return [
- Math.min(prev[0], target[minIndex]),
- Math.max(prev[1], target[maxIndex])
- ];
- }, [Number.MAX_VALUE, -Number.MAX_VALUE]);
- }
- };
- return reduceArrayMixin;
- });
- _registerModule(_modules, 'Stock/Indicators/PCIndicator.js', [_modules['Core/Utilities.js'], _modules['Mixins/ReduceArray.js'], _modules['Mixins/MultipleLines.js']], function (U, reduceArrayMixin, multipleLinesMixin) {
- /* *
- *
- * License: www.highcharts.com/license
- *
- * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
- *
- * */
- var merge = U.merge,
- seriesType = U.seriesType;
- var getArrayExtremes = reduceArrayMixin.getArrayExtremes;
- /**
- * The Price Channel series type.
- *
- * @private
- * @class
- * @name Highcharts.seriesTypes.pc
- *
- * @augments Highcharts.Series
- */
- seriesType('pc', 'sma',
- /**
- * Price channel (PC). This series requires the `linkedTo` option to be
- * set and should be loaded after the `stock/indicators/indicators.js`.
- *
- * @sample {highstock} stock/indicators/price-channel
- * Price Channel
- *
- * @extends plotOptions.sma
- * @since 7.0.0
- * @product highstock
- * @excluding allAreas, colorAxis, compare, compareBase, joinBy, keys,
- * navigatorOptions, pointInterval, pointIntervalUnit,
- * pointPlacement, pointRange, pointStart, showInNavigator,
- * stacking
- * @requires stock/indicators/indicators
- * @requires stock/indicators/price-channel
- * @optionparent plotOptions.pc
- */
- {
- /**
- * @excluding index
- */
- params: {
- period: 20
- },
- lineWidth: 1,
- topLine: {
- styles: {
- /**
- * Color of the top line. If not set, it's inherited from
- * [plotOptions.pc.color](#plotOptions.pc.color).
- *
- * @type {Highcharts.ColorString}
- */
- lineColor: '#7cb5ec #434348 #90ed7d #f7a35c #8085e9 #f15c80 #e4d354 #2b908f #f45b5b #91e8e1'.split(' ')[2],
- /**
- * Pixel width of the line.
- */
- lineWidth: 1
- }
- },
- bottomLine: {
- styles: {
- /**
- * Color of the bottom line. If not set, it's inherited from
- * [plotOptions.pc.color](#plotOptions.pc.color).
- *
- * @type {Highcharts.ColorString}
- */
- lineColor: '#7cb5ec #434348 #90ed7d #f7a35c #8085e9 #f15c80 #e4d354 #2b908f #f45b5b #91e8e1'.split(' ')[8],
- /**
- * Pixel width of the line.
- */
- lineWidth: 1
- }
- },
- dataGrouping: {
- approximation: 'averages'
- }
- },
- /**
- * @lends Highcharts.Series#
- */
- merge(multipleLinesMixin, {
- pointArrayMap: ['top', 'middle', 'bottom'],
- pointValKey: 'middle',
- nameBase: 'Price Channel',
- nameComponents: ['period'],
- linesApiNames: ['topLine', 'bottomLine'],
- getValues: function (series, params) {
- var period = params.period,
- xVal = series.xData,
- yVal = series.yData,
- yValLen = yVal ? yVal.length : 0,
- // 0- date, 1-top line, 2-middle line, 3-bottom line
- PC = [],
- // middle line, top line and bottom line
- ML,
- TL,
- BL,
- date,
- low = 2,
- high = 1,
- xData = [],
- yData = [],
- slicedY,
- extremes,
- i;
- if (yValLen < period) {
- return;
- }
- for (i = period; i <= yValLen; i++) {
- date = xVal[i - 1];
- slicedY = yVal.slice(i - period, i);
- extremes = getArrayExtremes(slicedY, low, high);
- TL = extremes[1];
- BL = extremes[0];
- ML = (TL + BL) / 2;
- PC.push([date, TL, ML, BL]);
- xData.push(date);
- yData.push([TL, ML, BL]);
- }
- return {
- values: PC,
- xData: xData,
- yData: yData
- };
- }
- }));
- /**
- * A Price channel indicator. If the [type](#series.pc.type) option is not
- * specified, it is inherited from [chart.type](#chart.type).
- *
- * @extends series,plotOptions.pc
- * @since 7.0.0
- * @product highstock
- * @excluding allAreas, colorAxis, compare, compareBase, dataParser, dataURL,
- * joinBy, keys, navigatorOptions, pointInterval,
- * pointIntervalUnit, pointPlacement, pointRange, pointStart,
- * showInNavigator, stacking
- * @requires stock/indicators/indicators
- * @requires stock/indicators/price-channel
- * @apioption series.pc
- */
- ''; // to include the above in the js output
- });
- _registerModule(_modules, 'Stock/Indicators/PriceEnvelopesIndicator.js', [_modules['Core/Globals.js'], _modules['Core/Utilities.js']], function (H, U) {
- /* *
- *
- * License: www.highcharts.com/license
- *
- * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
- *
- * */
- var isArray = U.isArray,
- merge = U.merge,
- seriesType = U.seriesType;
- var SMA = H.seriesTypes.sma;
- /**
- * The Price Envelopes series type.
- *
- * @private
- * @class
- * @name Highcharts.seriesTypes.priceenvelopes
- *
- * @augments Highcharts.Series
- */
- seriesType('priceenvelopes', 'sma',
- /**
- * Price envelopes indicator based on [SMA](#plotOptions.sma) calculations.
- * This series requires the `linkedTo` option to be set and should be loaded
- * after the `stock/indicators/indicators.js` file.
- *
- * @sample stock/indicators/price-envelopes
- * Price envelopes
- *
- * @extends plotOptions.sma
- * @since 6.0.0
- * @product highstock
- * @requires stock/indicators/indicators
- * @requires stock/indicators/price-envelopes
- * @optionparent plotOptions.priceenvelopes
- */
- {
- marker: {
- enabled: false
- },
- tooltip: {
- pointFormat: '<span style="color:{point.color}">\u25CF</span><b> {series.name}</b><br/>Top: {point.top}<br/>Middle: {point.middle}<br/>Bottom: {point.bottom}<br/>'
- },
- params: {
- period: 20,
- /**
- * Percentage above the moving average that should be displayed.
- * 0.1 means 110%. Relative to the calculated value.
- */
- topBand: 0.1,
- /**
- * Percentage below the moving average that should be displayed.
- * 0.1 means 90%. Relative to the calculated value.
- */
- bottomBand: 0.1
- },
- /**
- * Bottom line options.
- */
- bottomLine: {
- styles: {
- /**
- * Pixel width of the line.
- */
- lineWidth: 1,
- /**
- * Color of the line. If not set, it's inherited from
- * [plotOptions.priceenvelopes.color](
- * #plotOptions.priceenvelopes.color).
- *
- * @type {Highcharts.ColorString}
- */
- lineColor: void 0
- }
- },
- /**
- * Top line options.
- *
- * @extends plotOptions.priceenvelopes.bottomLine
- */
- topLine: {
- styles: {
- lineWidth: 1
- }
- },
- dataGrouping: {
- approximation: 'averages'
- }
- },
- /**
- * @lends Highcharts.Series#
- */
- {
- nameComponents: ['period', 'topBand', 'bottomBand'],
- nameBase: 'Price envelopes',
- pointArrayMap: ['top', 'middle', 'bottom'],
- parallelArrays: ['x', 'y', 'top', 'bottom'],
- pointValKey: 'middle',
- init: function () {
- SMA.prototype.init.apply(this, arguments);
- // Set default color for lines:
- this.options = merge({
- topLine: {
- styles: {
- lineColor: this.color
- }
- },
- bottomLine: {
- styles: {
- lineColor: this.color
- }
- }
- }, this.options);
- },
- toYData: function (point) {
- return [point.top, point.middle, point.bottom];
- },
- translate: function () {
- var indicator = this, translatedEnvelopes = ['plotTop', 'plotMiddle', 'plotBottom'];
- SMA.prototype.translate.apply(indicator);
- indicator.points.forEach(function (point) {
- [point.top, point.middle, point.bottom].forEach(function (value, i) {
- if (value !== null) {
- point[translatedEnvelopes[i]] =
- indicator.yAxis.toPixels(value, true);
- }
- });
- });
- },
- drawGraph: function () {
- var indicator = this,
- middleLinePoints = indicator.points,
- pointsLength = middleLinePoints.length,
- middleLineOptions = (indicator.options),
- middleLinePath = indicator.graph,
- gappedExtend = {
- options: {
- gapSize: middleLineOptions.gapSize
- }
- },
- deviations = [[],
- []], // top and bottom point place holders
- point;
- // Generate points for top and bottom lines:
- while (pointsLength--) {
- point = middleLinePoints[pointsLength];
- deviations[0].push({
- plotX: point.plotX,
- plotY: point.plotTop,
- isNull: point.isNull
- });
- deviations[1].push({
- plotX: point.plotX,
- plotY: point.plotBottom,
- isNull: point.isNull
- });
- }
- // Modify options and generate lines:
- ['topLine', 'bottomLine'].forEach(function (lineName, i) {
- indicator.points = deviations[i];
- indicator.options = merge(middleLineOptions[lineName].styles, gappedExtend);
- indicator.graph = indicator['graph' + lineName];
- SMA.prototype.drawGraph.call(indicator);
- // Now save lines:
- indicator['graph' + lineName] = indicator.graph;
- });
- // Restore options and draw a middle line:
- indicator.points = middleLinePoints;
- indicator.options = middleLineOptions;
- indicator.graph = middleLinePath;
- SMA.prototype.drawGraph.call(indicator);
- },
- getValues: function (series, params) {
- var period = params.period,
- topPercent = params.topBand,
- botPercent = params.bottomBand,
- xVal = series.xData,
- yVal = series.yData,
- yValLen = yVal ? yVal.length : 0,
- // 0- date, 1-top line, 2-middle line, 3-bottom line
- PE = [],
- // middle line, top line and bottom line
- ML,
- TL,
- BL,
- date,
- xData = [],
- yData = [],
- slicedX,
- slicedY,
- point,
- i;
- // Price envelopes requires close value
- if (xVal.length < period ||
- !isArray(yVal[0]) ||
- yVal[0].length !== 4) {
- return;
- }
- for (i = period; i <= yValLen; i++) {
- slicedX = xVal.slice(i - period, i);
- slicedY = yVal.slice(i - period, i);
- point = SMA.prototype.getValues.call(this, {
- xData: slicedX,
- yData: slicedY
- }, params);
- date = point.xData[0];
- ML = point.yData[0];
- TL = ML * (1 + topPercent);
- BL = ML * (1 - botPercent);
- PE.push([date, TL, ML, BL]);
- xData.push(date);
- yData.push([TL, ML, BL]);
- }
- return {
- values: PE,
- xData: xData,
- yData: yData
- };
- }
- });
- /**
- * A price envelopes indicator. If the [type](#series.priceenvelopes.type)
- * option is not specified, it is inherited from [chart.type](#chart.type).
- *
- * @extends series,plotOptions.priceenvelopes
- * @since 6.0.0
- * @excluding dataParser, dataURL
- * @product highstock
- * @requires stock/indicators/indicators
- * @requires stock/indicators/price-envelopes
- * @apioption series.priceenvelopes
- */
- ''; // to include the above in the js output
- });
- _registerModule(_modules, 'Stock/Indicators/PSARIndicator.js', [_modules['Core/Utilities.js']], function (U) {
- /* *
- *
- * Parabolic SAR indicator for Highstock
- *
- * (c) 2010-2020 Grzegorz Blachliński
- *
- * License: www.highcharts.com/license
- *
- * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
- *
- * */
- var seriesType = U.seriesType;
- /* eslint-disable require-jsdoc */
- // Utils:
- function toFixed(a, n) {
- return parseFloat(a.toFixed(n));
- }
- function calculateDirection(previousDirection, low, high, PSAR) {
- if ((previousDirection === 1 && low > PSAR) ||
- (previousDirection === -1 && high > PSAR)) {
- return 1;
- }
- return -1;
- }
- /* *
- * Method for calculating acceleration factor
- * dir - direction
- * pDir - previous Direction
- * eP - extreme point
- * pEP - previous extreme point
- * inc - increment for acceleration factor
- * maxAcc - maximum acceleration factor
- * initAcc - initial acceleration factor
- */
- function getAccelerationFactor(dir, pDir, eP, pEP, pAcc, inc, maxAcc, initAcc) {
- if (dir === pDir) {
- if (dir === 1 && (eP > pEP)) {
- return (pAcc === maxAcc) ? maxAcc : toFixed(pAcc + inc, 2);
- }
- if (dir === -1 && (eP < pEP)) {
- return (pAcc === maxAcc) ? maxAcc : toFixed(pAcc + inc, 2);
- }
- return pAcc;
- }
- return initAcc;
- }
- function getExtremePoint(high, low, previousDirection, previousExtremePoint) {
- if (previousDirection === 1) {
- return (high > previousExtremePoint) ? high : previousExtremePoint;
- }
- return (low < previousExtremePoint) ? low : previousExtremePoint;
- }
- function getEPMinusPSAR(EP, PSAR) {
- return EP - PSAR;
- }
- function getAccelerationFactorMultiply(accelerationFactor, EPMinusSAR) {
- return accelerationFactor * EPMinusSAR;
- }
- /* *
- * Method for calculating PSAR
- * pdir - previous direction
- * sDir - second previous Direction
- * PSAR - previous PSAR
- * pACCMultiply - previous acceleration factor multiply
- * sLow - second previous low
- * pLow - previous low
- * sHigh - second previous high
- * pHigh - previous high
- * pEP - previous extreme point
- */
- function getPSAR(pdir, sDir, PSAR, pACCMulti, sLow, pLow, pHigh, sHigh, pEP) {
- if (pdir === sDir) {
- if (pdir === 1) {
- return (PSAR + pACCMulti < Math.min(sLow, pLow)) ?
- PSAR + pACCMulti :
- Math.min(sLow, pLow);
- }
- return (PSAR + pACCMulti > Math.max(sHigh, pHigh)) ?
- PSAR + pACCMulti :
- Math.max(sHigh, pHigh);
- }
- return pEP;
- }
- /* eslint-enable require-jsdoc */
- /**
- * The Parabolic SAR series type.
- *
- * @private
- * @class
- * @name Highcharts.seriesTypes.psar
- *
- * @augments Highcharts.Series
- */
- seriesType('psar', 'sma',
- /**
- * Parabolic SAR. This series requires `linkedTo`
- * option to be set and should be loaded
- * after `stock/indicators/indicators.js` file.
- *
- * @sample stock/indicators/psar
- * Parabolic SAR Indicator
- *
- * @extends plotOptions.sma
- * @since 6.0.0
- * @product highstock
- * @requires stock/indicators/indicators
- * @requires stock/indicators/psar
- * @optionparent plotOptions.psar
- */
- {
- lineWidth: 0,
- marker: {
- enabled: true
- },
- states: {
- hover: {
- lineWidthPlus: 0
- }
- },
- /**
- * @excluding period
- */
- params: {
- /**
- * The initial value for acceleration factor.
- * Acceleration factor is starting with this value
- * and increases by specified increment each time
- * the extreme point makes a new high.
- * AF can reach a maximum of maxAccelerationFactor,
- * no matter how long the uptrend extends.
- */
- initialAccelerationFactor: 0.02,
- /**
- * The Maximum value for acceleration factor.
- * AF can reach a maximum of maxAccelerationFactor,
- * no matter how long the uptrend extends.
- */
- maxAccelerationFactor: 0.2,
- /**
- * Acceleration factor increases by increment each time
- * the extreme point makes a new high.
- *
- * @since 6.0.0
- */
- increment: 0.02,
- /**
- * Index from which PSAR is starting calculation
- *
- * @since 6.0.0
- */
- index: 2,
- /**
- * Number of maximum decimals that are used in PSAR calculations.
- *
- * @since 6.0.0
- */
- decimals: 4
- }
- }, {
- nameComponents: false,
- getValues: function (series, params) {
- var xVal = series.xData,
- yVal = series.yData,
- // Extreme point is the lowest low for falling and highest high
- // for rising psar - and we are starting with falling
- extremePoint = yVal[0][1],
- accelerationFactor = params.initialAccelerationFactor,
- maxAccelerationFactor = params.maxAccelerationFactor,
- increment = params.increment,
- // Set initial acc factor (for every new trend!)
- initialAccelerationFactor = params.initialAccelerationFactor,
- PSAR = yVal[0][2],
- decimals = params.decimals,
- index = params.index,
- PSARArr = [],
- xData = [],
- yData = [],
- previousDirection = 1,
- direction,
- EPMinusPSAR,
- accelerationFactorMultiply,
- newDirection,
- prevLow,
- prevPrevLow,
- prevHigh,
- prevPrevHigh,
- newExtremePoint,
- high,
- low,
- ind;
- if (index >= yVal.length) {
- return;
- }
- for (ind = 0; ind < index; ind++) {
- extremePoint = Math.max(yVal[ind][1], extremePoint);
- PSAR = Math.min(yVal[ind][2], toFixed(PSAR, decimals));
- }
- direction = (yVal[ind][1] > PSAR) ? 1 : -1;
- EPMinusPSAR = getEPMinusPSAR(extremePoint, PSAR);
- accelerationFactor = params.initialAccelerationFactor;
- accelerationFactorMultiply = getAccelerationFactorMultiply(accelerationFactor, EPMinusPSAR);
- PSARArr.push([xVal[index], PSAR]);
- xData.push(xVal[index]);
- yData.push(toFixed(PSAR, decimals));
- for (ind = index + 1; ind < yVal.length; ind++) {
- prevLow = yVal[ind - 1][2];
- prevPrevLow = yVal[ind - 2][2];
- prevHigh = yVal[ind - 1][1];
- prevPrevHigh = yVal[ind - 2][1];
- high = yVal[ind][1];
- low = yVal[ind][2];
- // Null points break PSAR
- if (prevPrevLow !== null &&
- prevPrevHigh !== null &&
- prevLow !== null &&
- prevHigh !== null &&
- high !== null &&
- low !== null) {
- PSAR = getPSAR(direction, previousDirection, PSAR, accelerationFactorMultiply, prevPrevLow, prevLow, prevHigh, prevPrevHigh, extremePoint);
- newExtremePoint = getExtremePoint(high, low, direction, extremePoint);
- newDirection = calculateDirection(previousDirection, low, high, PSAR);
- accelerationFactor = getAccelerationFactor(newDirection, direction, newExtremePoint, extremePoint, accelerationFactor, increment, maxAccelerationFactor, initialAccelerationFactor);
- EPMinusPSAR = getEPMinusPSAR(newExtremePoint, PSAR);
- accelerationFactorMultiply = getAccelerationFactorMultiply(accelerationFactor, EPMinusPSAR);
- PSARArr.push([xVal[ind], toFixed(PSAR, decimals)]);
- xData.push(xVal[ind]);
- yData.push(toFixed(PSAR, decimals));
- previousDirection = direction;
- direction = newDirection;
- extremePoint = newExtremePoint;
- }
- }
- return {
- values: PSARArr,
- xData: xData,
- yData: yData
- };
- }
- });
- /**
- * A `PSAR` series. If the [type](#series.psar.type) option is not specified, it
- * is inherited from [chart.type](#chart.type).
- *
- * @extends series,plotOptions.psar
- * @since 6.0.0
- * @product highstock
- * @excluding dataParser, dataURL
- * @requires stock/indicators/indicators
- * @requires stock/indicators/psar
- * @apioption series.psar
- */
- ''; // to include the above in the js output
- });
- _registerModule(_modules, 'Stock/Indicators/ROCIndicator.js', [_modules['Core/Utilities.js']], function (U) {
- /* *
- *
- * (c) 2010-2020 Kacper Madej
- *
- * License: www.highcharts.com/license
- *
- * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
- *
- * */
- var isArray = U.isArray,
- seriesType = U.seriesType;
- /* eslint-disable require-jsdoc */
- // Utils:
- function populateAverage(xVal, yVal, i, period, index) {
- /* Calculated as:
- (Closing Price [today] - Closing Price [n days ago]) /
- Closing Price [n days ago] * 100
- Return y as null when avoiding division by zero */
- var nDaysAgoY,
- rocY;
- if (index < 0) {
- // y data given as an array of values
- nDaysAgoY = yVal[i - period];
- rocY = nDaysAgoY ?
- (yVal[i] - nDaysAgoY) / nDaysAgoY * 100 :
- null;
- }
- else {
- // y data given as an array of arrays and the index should be used
- nDaysAgoY = yVal[i - period][index];
- rocY = nDaysAgoY ?
- (yVal[i][index] - nDaysAgoY) / nDaysAgoY * 100 :
- null;
- }
- return [xVal[i], rocY];
- }
- /* eslint-enable require-jsdoc */
- /**
- * The ROC series type.
- *
- * @private
- * @class
- * @name Highcharts.seriesTypes.roc
- *
- * @augments Highcharts.Series
- */
- seriesType('roc', 'sma',
- /**
- * Rate of change indicator (ROC). The indicator value for each point
- * is defined as:
- *
- * `(C - Cn) / Cn * 100`
- *
- * where: `C` is the close value of the point of the same x in the
- * linked series and `Cn` is the close value of the point `n` periods
- * ago. `n` is set through [period](#plotOptions.roc.params.period).
- *
- * This series requires `linkedTo` option to be set.
- *
- * @sample stock/indicators/roc
- * Rate of change indicator
- *
- * @extends plotOptions.sma
- * @since 6.0.0
- * @product highstock
- * @requires stock/indicators/indicators
- * @requires stock/indicators/roc
- * @optionparent plotOptions.roc
- */
- {
- params: {
- index: 3,
- period: 9
- }
- },
- /**
- * @lends Highcharts.Series#
- */
- {
- nameBase: 'Rate of Change',
- getValues: function (series, params) {
- var period = params.period,
- xVal = series.xData,
- yVal = series.yData,
- yValLen = yVal ? yVal.length : 0,
- ROC = [],
- xData = [],
- yData = [],
- i,
- index = -1,
- ROCPoint;
- // Period is used as a number of time periods ago, so we need more
- // (at least 1 more) data than the period value
- if (xVal.length <= period) {
- return;
- }
- // Switch index for OHLC / Candlestick / Arearange
- if (isArray(yVal[0])) {
- index = params.index;
- }
- // i = period <-- skip first N-points
- // Calculate value one-by-one for each period in visible data
- for (i = period; i < yValLen; i++) {
- ROCPoint = populateAverage(xVal, yVal, i, period, index);
- ROC.push(ROCPoint);
- xData.push(ROCPoint[0]);
- yData.push(ROCPoint[1]);
- }
- return {
- values: ROC,
- xData: xData,
- yData: yData
- };
- }
- });
- /**
- * A `ROC` series. If the [type](#series.wma.type) option is not
- * specified, it is inherited from [chart.type](#chart.type).
- *
- * Rate of change indicator (ROC). The indicator value for each point
- * is defined as:
- *
- * `(C - Cn) / Cn * 100`
- *
- * where: `C` is the close value of the point of the same x in the
- * linked series and `Cn` is the close value of the point `n` periods
- * ago. `n` is set through [period](#series.roc.params.period).
- *
- * This series requires `linkedTo` option to be set.
- *
- * @extends series,plotOptions.roc
- * @since 6.0.0
- * @product highstock
- * @excluding dataParser, dataURL
- * @requires stock/indicators/indicators
- * @requires stock/indicators/roc
- * @apioption series.roc
- */
- ''; // to include the above in the js output
- });
- _registerModule(_modules, 'Stock/Indicators/RSIIndicator.js', [_modules['Core/Utilities.js']], function (U) {
- /* *
- *
- * License: www.highcharts.com/license
- *
- * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
- *
- * */
- var isArray = U.isArray,
- seriesType = U.seriesType;
- /* eslint-disable require-jsdoc */
- // Utils:
- function toFixed(a, n) {
- return parseFloat(a.toFixed(n));
- }
- /* eslint-enable require-jsdoc */
- /**
- * The RSI series type.
- *
- * @private
- * @class
- * @name Highcharts.seriesTypes.rsi
- *
- * @augments Highcharts.Series
- */
- seriesType('rsi', 'sma',
- /**
- * Relative strength index (RSI) technical indicator. This series
- * requires the `linkedTo` option to be set and should be loaded after
- * the `stock/indicators/indicators.js` file.
- *
- * @sample stock/indicators/rsi
- * RSI indicator
- *
- * @extends plotOptions.sma
- * @since 6.0.0
- * @product highstock
- * @requires stock/indicators/indicators
- * @requires stock/indicators/rsi
- * @optionparent plotOptions.rsi
- */
- {
- /**
- * @excluding index
- */
- params: {
- period: 14,
- /**
- * Number of maximum decimals that are used in RSI calculations.
- */
- decimals: 4
- }
- },
- /**
- * @lends Highcharts.Series#
- */
- {
- getValues: function (series, params) {
- var period = params.period,
- xVal = series.xData,
- yVal = series.yData,
- yValLen = yVal ? yVal.length : 0,
- decimals = params.decimals,
- // RSI starts calculations from the second point
- // Cause we need to calculate change between two points
- range = 1,
- RSI = [],
- xData = [],
- yData = [],
- index = 3,
- gain = 0,
- loss = 0,
- RSIPoint,
- change,
- avgGain,
- avgLoss,
- i;
- // RSI requires close value
- if ((xVal.length < period) || !isArray(yVal[0]) ||
- yVal[0].length !== 4) {
- return;
- }
- // Calculate changes for first N points
- while (range < period) {
- change = toFixed(yVal[range][index] - yVal[range - 1][index], decimals);
- if (change > 0) {
- gain += change;
- }
- else {
- loss += Math.abs(change);
- }
- range++;
- }
- // Average for first n-1 points:
- avgGain = toFixed(gain / (period - 1), decimals);
- avgLoss = toFixed(loss / (period - 1), decimals);
- for (i = range; i < yValLen; i++) {
- change = toFixed(yVal[i][index] - yVal[i - 1][index], decimals);
- if (change > 0) {
- gain = change;
- loss = 0;
- }
- else {
- gain = 0;
- loss = Math.abs(change);
- }
- // Calculate smoothed averages, RS, RSI values:
- avgGain = toFixed((avgGain * (period - 1) + gain) / period, decimals);
- avgLoss = toFixed((avgLoss * (period - 1) + loss) / period, decimals);
- // If average-loss is equal zero, then by definition RSI is set
- // to 100:
- if (avgLoss === 0) {
- RSIPoint = 100;
- // If average-gain is equal zero, then by definition RSI is set
- // to 0:
- }
- else if (avgGain === 0) {
- RSIPoint = 0;
- }
- else {
- RSIPoint = toFixed(100 - (100 / (1 + (avgGain / avgLoss))), decimals);
- }
- RSI.push([xVal[i], RSIPoint]);
- xData.push(xVal[i]);
- yData.push(RSIPoint);
- }
- return {
- values: RSI,
- xData: xData,
- yData: yData
- };
- }
- });
- /**
- * A `RSI` series. If the [type](#series.rsi.type) option is not
- * specified, it is inherited from [chart.type](#chart.type).
- *
- * @extends series,plotOptions.rsi
- * @since 6.0.0
- * @product highstock
- * @excluding dataParser, dataURL
- * @requires stock/indicators/indicators
- * @requires stock/indicators/rsi
- * @apioption series.rsi
- */
- ''; // to include the above in the js output
- });
- _registerModule(_modules, 'Stock/Indicators/StochasticIndicator.js', [_modules['Core/Globals.js'], _modules['Core/Utilities.js'], _modules['Mixins/ReduceArray.js'], _modules['Mixins/MultipleLines.js']], function (H, U, reduceArrayMixin, multipleLinesMixin) {
- /* *
- *
- * License: www.highcharts.com/license
- *
- * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
- *
- * */
- var isArray = U.isArray,
- merge = U.merge,
- seriesType = U.seriesType;
- var SMA = H.seriesTypes.sma,
- getArrayExtremes = reduceArrayMixin.getArrayExtremes;
- /**
- * The Stochastic series type.
- *
- * @private
- * @class
- * @name Highcharts.seriesTypes.stochastic
- *
- * @augments Highcharts.Series
- */
- seriesType('stochastic', 'sma',
- /**
- * Stochastic oscillator. This series requires the `linkedTo` option to be
- * set and should be loaded after the `stock/indicators/indicators.js` file.
- *
- * @sample stock/indicators/stochastic
- * Stochastic oscillator
- *
- * @extends plotOptions.sma
- * @since 6.0.0
- * @product highstock
- * @excluding allAreas, colorAxis, joinBy, keys, navigatorOptions,
- * pointInterval, pointIntervalUnit, pointPlacement,
- * pointRange, pointStart, showInNavigator, stacking
- * @requires stock/indicators/indicators
- * @requires stock/indicators/stochastic
- * @optionparent plotOptions.stochastic
- */
- {
- /**
- * @excluding index, period
- */
- params: {
- /**
- * Periods for Stochastic oscillator: [%K, %D].
- *
- * @type {Array<number,number>}
- * @default [14, 3]
- */
- periods: [14, 3]
- },
- marker: {
- enabled: false
- },
- tooltip: {
- pointFormat: '<span style="color:{point.color}">\u25CF</span><b> {series.name}</b><br/>%K: {point.y}<br/>%D: {point.smoothed}<br/>'
- },
- /**
- * Smoothed line options.
- */
- smoothedLine: {
- /**
- * Styles for a smoothed line.
- */
- styles: {
- /**
- * Pixel width of the line.
- */
- lineWidth: 1,
- /**
- * Color of the line. If not set, it's inherited from
- * [plotOptions.stochastic.color
- * ](#plotOptions.stochastic.color).
- *
- * @type {Highcharts.ColorString}
- */
- lineColor: void 0
- }
- },
- dataGrouping: {
- approximation: 'averages'
- }
- },
- /**
- * @lends Highcharts.Series#
- */
- merge(multipleLinesMixin, {
- nameComponents: ['periods'],
- nameBase: 'Stochastic',
- pointArrayMap: ['y', 'smoothed'],
- parallelArrays: ['x', 'y', 'smoothed'],
- pointValKey: 'y',
- linesApiNames: ['smoothedLine'],
- init: function () {
- SMA.prototype.init.apply(this, arguments);
- // Set default color for lines:
- this.options = merge({
- smoothedLine: {
- styles: {
- lineColor: this.color
- }
- }
- }, this.options);
- },
- getValues: function (series, params) {
- var periodK = params.periods[0],
- periodD = params.periods[1],
- xVal = series.xData,
- yVal = series.yData,
- yValLen = yVal ? yVal.length : 0,
- // 0- date, 1-%K, 2-%D
- SO = [],
- xData = [],
- yData = [],
- slicedY,
- close = 3,
- low = 2,
- high = 1,
- CL,
- HL,
- LL,
- K,
- D = null,
- points,
- extremes,
- i;
- // Stochastic requires close value
- if (yValLen < periodK ||
- !isArray(yVal[0]) ||
- yVal[0].length !== 4) {
- return;
- }
- // For a N-period, we start from N-1 point, to calculate Nth point
- // That is why we later need to comprehend slice() elements list
- // with (+1)
- for (i = periodK - 1; i < yValLen; i++) {
- slicedY = yVal.slice(i - periodK + 1, i + 1);
- // Calculate %K
- extremes = getArrayExtremes(slicedY, low, high);
- LL = extremes[0]; // Lowest low in %K periods
- CL = yVal[i][close] - LL;
- HL = extremes[1] - LL;
- K = CL / HL * 100;
- xData.push(xVal[i]);
- yData.push([K, null]);
- // Calculate smoothed %D, which is SMA of %K
- if (i >= (periodK - 1) + (periodD - 1)) {
- points = SMA.prototype.getValues.call(this, {
- xData: xData.slice(-periodD),
- yData: yData.slice(-periodD)
- }, {
- period: periodD
- });
- D = points.yData[0];
- }
- SO.push([xVal[i], K, D]);
- yData[yData.length - 1][1] = D;
- }
- return {
- values: SO,
- xData: xData,
- yData: yData
- };
- }
- }));
- /**
- * A Stochastic indicator. If the [type](#series.stochastic.type) option is not
- * specified, it is inherited from [chart.type](#chart.type).
- *
- * @extends series,plotOptions.stochastic
- * @since 6.0.0
- * @product highstock
- * @excluding allAreas, colorAxis, dataParser, dataURL, joinBy, keys,
- * navigatorOptions, pointInterval, pointIntervalUnit,
- * pointPlacement, pointRange, pointStart, showInNavigator, stacking
- * @requires stock/indicators/indicators
- * @requires stock/indicators/stochastic
- * @apioption series.stochastic
- */
- ''; // to include the above in the js output
- });
- _registerModule(_modules, 'Stock/Indicators/SlowStochasticIndicator.js', [_modules['Core/Globals.js'], _modules['Core/Utilities.js'], _modules['Mixins/IndicatorRequired.js']], function (H, U, requiredIndicator) {
- /* *
- *
- * License: www.highcharts.com/license
- *
- * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
- *
- * */
- var seriesType = U.seriesType;
- var seriesTypes = H.seriesTypes;
- /**
- * The Slow Stochastic series type.
- *
- * @private
- * @class
- * @name Highcharts.seriesTypes.slowstochastic
- *
- * @augments Highcharts.Series
- */
- seriesType('slowstochastic', 'stochastic',
- /**
- * Slow Stochastic oscillator. This series requires the `linkedTo` option
- * to be set and should be loaded after `stock/indicators/indicators.js`
- * and `stock/indicators/stochastic.js` files.
- *
- * @sample stock/indicators/slow-stochastic
- * Slow Stochastic oscillator
- *
- * @extends plotOptions.stochastic
- * @since 8.0.0
- * @product highstock
- * @requires stock/indicators/indicators
- * @requires stock/indicators/stochastic
- * @requires stock/indicators/slowstochastic
- * @optionparent plotOptions.slowstochastic
- */
- {
- params: {
- /**
- * Periods for Slow Stochastic oscillator: [%K, %D, SMA(%D)].
- *
- * @type {Array<number,number,number>}
- * @default [14, 3, 3]
- */
- periods: [14, 3, 3]
- }
- },
- /**
- * @lends Highcharts.Series#
- */
- {
- nameBase: 'Slow Stochastic',
- init: function () {
- var args = arguments,
- ctx = this;
- requiredIndicator.isParentLoaded(H.seriesTypes.stochastic, 'stochastic', ctx.type, function (indicator) {
- indicator.prototype.init.apply(ctx, args);
- return;
- });
- },
- getValues: function (series, params) {
- var periods = params.periods,
- fastValues = seriesTypes.stochastic.prototype.getValues.call(this,
- series,
- params),
- slowValues = {
- values: [],
- xData: [],
- yData: []
- };
- var i = 0;
- if (!fastValues) {
- return;
- }
- slowValues.xData = fastValues.xData.slice(periods[1] - 1);
- var fastYData = fastValues.yData.slice(periods[1] - 1);
- // Get SMA(%D)
- var smoothedValues = seriesTypes.sma.prototype.getValues.call(this, {
- xData: slowValues.xData,
- yData: fastYData
- }, {
- index: 1,
- period: periods[2]
- });
- if (!smoothedValues) {
- return;
- }
- var xDataLen = slowValues.xData.length;
- // Format data
- for (; i < xDataLen; i++) {
- slowValues.yData[i] = [
- fastYData[i][1],
- smoothedValues.yData[i - periods[2] + 1] || null
- ];
- slowValues.values[i] = [
- slowValues.xData[i],
- fastYData[i][1],
- smoothedValues.yData[i - periods[2] + 1] || null
- ];
- }
- return slowValues;
- }
- });
- /**
- * A Slow Stochastic indicator. If the [type](#series.slowstochastic.type)
- * option is not specified, it is inherited from [chart.type](#chart.type).
- *
- * @extends series,plotOptions.slowstochastic
- * @since 8.0.0
- * @product highstock
- * @requires stock/indicators/indicators
- * @requires stock/indicators/stochastic
- * @requires stock/indicators/slowstochastic
- * @apioption series.slowstochastic
- */
- ''; // to include the above in the js output
- });
- _registerModule(_modules, 'Stock/Indicators/SupertrendIndicator.js', [_modules['Core/Globals.js'], _modules['Core/Utilities.js']], function (H, U) {
- /* *
- *
- * License: www.highcharts.com/license
- *
- * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
- *
- * */
- var correctFloat = U.correctFloat,
- merge = U.merge,
- seriesType = U.seriesType;
- var isArray = U.isArray,
- objectEach = U.objectEach;
- var ATR = H.seriesTypes.atr,
- SMA = H.seriesTypes.sma;
- /* eslint-disable require-jsdoc */
- // Utils:
- function createPointObj(mainSeries, index, close) {
- return {
- index: index,
- close: mainSeries.yData[index][close],
- x: mainSeries.xData[index]
- };
- }
- /* eslint-enable require-jsdoc */
- /**
- * The Supertrend series type.
- *
- * @private
- * @class
- * @name Highcharts.seriesTypes.supertrend
- *
- * @augments Highcharts.Series
- */
- seriesType('supertrend', 'sma',
- /**
- * Supertrend indicator. This series requires the `linkedTo` option to be
- * set and should be loaded after the `stock/indicators/indicators.js` and
- * `stock/indicators/sma.js`.
- *
- * @sample {highstock} stock/indicators/supertrend
- * Supertrend indicator
- *
- * @extends plotOptions.sma
- * @since 7.0.0
- * @product highstock
- * @excluding allAreas, cropThreshold, negativeColor, colorAxis, joinBy,
- * keys, navigatorOptions, pointInterval, pointIntervalUnit,
- * pointPlacement, pointRange, pointStart, showInNavigator,
- * stacking, threshold
- * @requires stock/indicators/indicators
- * @requires stock/indicators/supertrend
- * @optionparent plotOptions.supertrend
- */
- {
- /**
- * Paramters used in calculation of Supertrend indicator series points.
- *
- * @excluding index
- */
- params: {
- /**
- * Multiplier for Supertrend Indicator.
- */
- multiplier: 3,
- /**
- * The base period for indicator Supertrend Indicator calculations.
- * This is the number of data points which are taken into account
- * for the indicator calculations.
- */
- period: 10
- },
- /**
- * Color of the Supertrend series line that is beneath the main series.
- *
- * @sample {highstock} stock/indicators/supertrend/
- * Example with risingTrendColor
- *
- * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
- */
- risingTrendColor: '#06B535',
- /**
- * Color of the Supertrend series line that is above the main series.
- *
- * @sample {highstock} stock/indicators/supertrend/
- * Example with fallingTrendColor
- *
- * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
- */
- fallingTrendColor: '#F21313',
- /**
- * The styles for the Supertrend line that intersect main series.
- *
- * @sample {highstock} stock/indicators/supertrend/
- * Example with changeTrendLine
- */
- changeTrendLine: {
- styles: {
- /**
- * Pixel width of the line.
- */
- lineWidth: 1,
- /**
- * Color of the line.
- *
- * @type {Highcharts.ColorString}
- */
- lineColor: '#333333',
- /**
- * The dash or dot style of the grid lines. For possible
- * values, see
- * [this demonstration](https://jsfiddle.net/gh/get/library/pure/highcharts/highcharts/tree/master/samples/highcharts/plotoptions/series-dashstyle-all/).
- *
- * @sample {highcharts} highcharts/yaxis/gridlinedashstyle/
- * Long dashes
- * @sample {highstock} stock/xaxis/gridlinedashstyle/
- * Long dashes
- *
- * @type {Highcharts.DashStyleValue}
- * @since 7.0.0
- */
- dashStyle: 'LongDash'
- }
- }
- },
- /**
- * @lends Highcharts.Series.prototype
- */
- {
- nameBase: 'Supertrend',
- nameComponents: ['multiplier', 'period'],
- requiredIndicators: ['atr'],
- init: function () {
- var options,
- parentOptions;
- SMA.prototype.init.apply(this, arguments);
- options = this.options;
- parentOptions = this.linkedParent.options;
- // Indicator cropThreshold has to be equal linked series one
- // reduced by period due to points comparison in drawGraph method
- // (#9787)
- options.cropThreshold = (parentOptions.cropThreshold -
- (options.params.period - 1));
- },
- drawGraph: function () {
- var indicator = this,
- indicOptions = indicator.options,
- // Series that indicator is linked to
- mainSeries = indicator.linkedParent,
- mainLinePoints = (mainSeries ? mainSeries.points : []),
- indicPoints = indicator.points,
- indicPath = indicator.graph,
- indicPointsLen = indicPoints.length,
- // Points offset between lines
- tempOffset = mainLinePoints.length - indicPointsLen,
- offset = tempOffset > 0 ? tempOffset : 0,
- // @todo: fix when ichi-moku indicator is merged to master.
- gappedExtend = {
- options: {
- gapSize: indicOptions.gapSize
- }
- },
- // Sorted supertrend points array
- groupedPoitns = {
- top: [],
- bottom: [],
- intersect: [] // Change trend line points
- },
- // Options for trend lines
- supertrendLineOptions = {
- top: {
- styles: {
- lineWidth: indicOptions.lineWidth,
- lineColor: (indicOptions.fallingTrendColor ||
- indicOptions.color),
- dashStyle: indicOptions.dashStyle
- }
- },
- bottom: {
- styles: {
- lineWidth: indicOptions.lineWidth,
- lineColor: (indicOptions.risingTrendColor ||
- indicOptions.color),
- dashStyle: indicOptions.dashStyle
- }
- },
- intersect: indicOptions.changeTrendLine
- },
- close = 3,
- // Supertrend line point
- point,
- // Supertrend line next point (has smaller x pos than point)
- nextPoint,
- // Main series points
- mainPoint,
- nextMainPoint,
- // Used when supertrend and main points are shifted
- // relative to each other
- prevMainPoint,
- prevPrevMainPoint,
- // Used when particular point color is set
- pointColor,
- // Temporary points that fill groupedPoitns array
- newPoint,
- newNextPoint;
- // Loop which sort supertrend points
- while (indicPointsLen--) {
- point = indicPoints[indicPointsLen];
- nextPoint = indicPoints[indicPointsLen - 1];
- mainPoint = mainLinePoints[indicPointsLen - 1 + offset];
- nextMainPoint = mainLinePoints[indicPointsLen - 2 + offset];
- prevMainPoint = mainLinePoints[indicPointsLen + offset];
- prevPrevMainPoint = mainLinePoints[indicPointsLen + offset + 1];
- pointColor = point.options.color;
- newPoint = {
- x: point.x,
- plotX: point.plotX,
- plotY: point.plotY,
- isNull: false
- };
- // When mainPoint is the last one (left plot area edge)
- // but supertrend has additional one
- if (!nextMainPoint &&
- mainPoint && mainSeries.yData[mainPoint.index - 1]) {
- nextMainPoint = createPointObj(mainSeries, mainPoint.index - 1, close);
- }
- // When prevMainPoint is the last one (right plot area edge)
- // but supertrend has additional one (and points are shifted)
- if (!prevPrevMainPoint &&
- prevMainPoint && mainSeries.yData[prevMainPoint.index + 1]) {
- prevPrevMainPoint = createPointObj(mainSeries, prevMainPoint.index + 1, close);
- }
- // When points are shifted (right or left plot area edge)
- if (!mainPoint &&
- nextMainPoint && mainSeries.yData[nextMainPoint.index + 1]) {
- mainPoint = createPointObj(mainSeries, nextMainPoint.index + 1, close);
- }
- else if (!mainPoint &&
- prevMainPoint && mainSeries.yData[prevMainPoint.index - 1]) {
- mainPoint = createPointObj(mainSeries, prevMainPoint.index - 1, close);
- }
- // Check if points are shifted relative to each other
- if (point &&
- mainPoint &&
- prevMainPoint &&
- nextMainPoint &&
- point.x !== mainPoint.x) {
- if (point.x === prevMainPoint.x) {
- nextMainPoint = mainPoint;
- mainPoint = prevMainPoint;
- }
- else if (point.x === nextMainPoint.x) {
- mainPoint = nextMainPoint;
- nextMainPoint = {
- close: mainSeries.yData[mainPoint.index - 1][close],
- x: mainSeries.xData[mainPoint.index - 1]
- };
- }
- else if (prevPrevMainPoint && point.x === prevPrevMainPoint.x) {
- mainPoint = prevPrevMainPoint;
- nextMainPoint = prevMainPoint;
- }
- }
- if (nextPoint && nextMainPoint && mainPoint) {
- newNextPoint = {
- x: nextPoint.x,
- plotX: nextPoint.plotX,
- plotY: nextPoint.plotY,
- isNull: false
- };
- if (point.y >= mainPoint.close &&
- nextPoint.y >= nextMainPoint.close) {
- point.color = (pointColor || indicOptions.fallingTrendColor ||
- indicOptions.color);
- groupedPoitns.top.push(newPoint);
- }
- else if (point.y < mainPoint.close &&
- nextPoint.y < nextMainPoint.close) {
- point.color = (pointColor || indicOptions.risingTrendColor ||
- indicOptions.color);
- groupedPoitns.bottom.push(newPoint);
- }
- else {
- groupedPoitns.intersect.push(newPoint);
- groupedPoitns.intersect.push(newNextPoint);
- // Additional null point to make a gap in line
- groupedPoitns.intersect.push(merge(newNextPoint, {
- isNull: true
- }));
- if (point.y >= mainPoint.close &&
- nextPoint.y < nextMainPoint.close) {
- point.color = (pointColor || indicOptions.fallingTrendColor ||
- indicOptions.color);
- nextPoint.color = (pointColor || indicOptions.risingTrendColor ||
- indicOptions.color);
- groupedPoitns.top.push(newPoint);
- groupedPoitns.top.push(merge(newNextPoint, {
- isNull: true
- }));
- }
- else if (point.y < mainPoint.close &&
- nextPoint.y >= nextMainPoint.close) {
- point.color = (pointColor || indicOptions.risingTrendColor ||
- indicOptions.color);
- nextPoint.color = (pointColor || indicOptions.fallingTrendColor ||
- indicOptions.color);
- groupedPoitns.bottom.push(newPoint);
- groupedPoitns.bottom.push(merge(newNextPoint, {
- isNull: true
- }));
- }
- }
- }
- else if (mainPoint) {
- if (point.y >= mainPoint.close) {
- point.color = (pointColor || indicOptions.fallingTrendColor ||
- indicOptions.color);
- groupedPoitns.top.push(newPoint);
- }
- else {
- point.color = (pointColor || indicOptions.risingTrendColor ||
- indicOptions.color);
- groupedPoitns.bottom.push(newPoint);
- }
- }
- }
- // Generate lines:
- objectEach(groupedPoitns, function (values, lineName) {
- indicator.points = values;
- indicator.options = merge(supertrendLineOptions[lineName].styles, gappedExtend);
- indicator.graph = indicator['graph' + lineName + 'Line'];
- SMA.prototype.drawGraph.call(indicator);
- // Now save line
- indicator['graph' + lineName + 'Line'] = indicator.graph;
- });
- // Restore options:
- indicator.points = indicPoints;
- indicator.options = indicOptions;
- indicator.graph = indicPath;
- },
- // Supertrend (Multiplier, Period) Formula:
- // BASIC UPPERBAND = (HIGH + LOW) / 2 + Multiplier * ATR(Period)
- // BASIC LOWERBAND = (HIGH + LOW) / 2 - Multiplier * ATR(Period)
- // FINAL UPPERBAND =
- // IF(
- // Current BASICUPPERBAND < Previous FINAL UPPERBAND AND
- // Previous Close > Previous FINAL UPPERBAND
- // ) THEN (Current BASIC UPPERBAND)
- // ELSE (Previous FINALUPPERBAND)
- // FINAL LOWERBAND =
- // IF(
- // Current BASIC LOWERBAND > Previous FINAL LOWERBAND AND
- // Previous Close < Previous FINAL LOWERBAND
- // ) THEN (Current BASIC LOWERBAND)
- // ELSE (Previous FINAL LOWERBAND)
- // SUPERTREND =
- // IF(
- // Previous Supertrend == Previous FINAL UPPERBAND AND
- // Current Close < Current FINAL UPPERBAND
- // ) THAN Current FINAL UPPERBAND
- // ELSE IF(
- // Previous Supertrend == Previous FINAL LOWERBAND AND
- // Current Close < Current FINAL LOWERBAND
- // ) THAN Current FINAL UPPERBAND
- // ELSE IF(
- // Previous Supertrend == Previous FINAL UPPERBAND AND
- // Current Close > Current FINAL UPPERBAND
- // ) THAN Current FINAL LOWERBAND
- // ELSE IF(
- // Previous Supertrend == Previous FINAL LOWERBAND AND
- // Current Close > Current FINAL LOWERBAND
- // ) THAN Current FINAL LOWERBAND
- getValues: function (series, params) {
- var period = params.period,
- multiplier = params.multiplier,
- xVal = series.xData,
- yVal = series.yData,
- ATRData = [],
- // 0- date, 1- Supertrend indicator
- ST = [],
- xData = [],
- yData = [],
- close = 3,
- low = 2,
- high = 1,
- periodsOffset = (period === 0) ? 0 : period - 1,
- basicUp,
- basicDown,
- finalUp = [],
- finalDown = [],
- supertrend,
- prevFinalUp,
- prevFinalDown,
- prevST, // previous Supertrend
- prevY,
- y,
- i;
- if ((xVal.length <= period) || !isArray(yVal[0]) ||
- yVal[0].length !== 4 || period < 0) {
- return;
- }
- ATRData = ATR.prototype.getValues.call(this, series, {
- period: period
- }).yData;
- for (i = 0; i < ATRData.length; i++) {
- y = yVal[periodsOffset + i];
- prevY = yVal[periodsOffset + i - 1] || [];
- prevFinalUp = finalUp[i - 1];
- prevFinalDown = finalDown[i - 1];
- prevST = yData[i - 1];
- if (i === 0) {
- prevFinalUp = prevFinalDown = prevST = 0;
- }
- basicUp = correctFloat((y[high] + y[low]) / 2 + multiplier * ATRData[i]);
- basicDown = correctFloat((y[high] + y[low]) / 2 - multiplier * ATRData[i]);
- if ((basicUp < prevFinalUp) ||
- (prevY[close] > prevFinalUp)) {
- finalUp[i] = basicUp;
- }
- else {
- finalUp[i] = prevFinalUp;
- }
- if ((basicDown > prevFinalDown) ||
- (prevY[close] < prevFinalDown)) {
- finalDown[i] = basicDown;
- }
- else {
- finalDown[i] = prevFinalDown;
- }
- if (prevST === prevFinalUp && y[close] < finalUp[i] ||
- prevST === prevFinalDown && y[close] < finalDown[i]) {
- supertrend = finalUp[i];
- }
- else if (prevST === prevFinalUp && y[close] > finalUp[i] ||
- prevST === prevFinalDown && y[close] > finalDown[i]) {
- supertrend = finalDown[i];
- }
- ST.push([xVal[periodsOffset + i], supertrend]);
- xData.push(xVal[periodsOffset + i]);
- yData.push(supertrend);
- }
- return {
- values: ST,
- xData: xData,
- yData: yData
- };
- }
- });
- /**
- * A `Supertrend indicator` series. If the [type](#series.supertrend.type)
- * option is not specified, it is inherited from [chart.type](#chart.type).
- *
- * @extends series,plotOptions.supertrend
- * @since 7.0.0
- * @product highstock
- * @excluding allAreas, colorAxis, cropThreshold, data, dataParser, dataURL,
- * joinBy, keys, navigatorOptions, negativeColor, pointInterval,
- * pointIntervalUnit, pointPlacement, pointRange, pointStart,
- * showInNavigator, stacking, threshold
- * @requires stock/indicators/indicators
- * @requires stock/indicators/supertrend
- * @apioption series.supertrend
- */
- ''; // to include the above in the js output
- });
- _registerModule(_modules, 'Stock/Indicators/VBPIndicator.js', [_modules['Core/Globals.js'], _modules['Core/Series/Point.js'], _modules['Core/Utilities.js']], function (H, Point, U) {
- /* *
- *
- * (c) 2010-2020 Paweł Dalek
- *
- * Volume By Price (VBP) indicator for Highstock
- *
- * License: www.highcharts.com/license
- *
- * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
- *
- * */
- var addEvent = U.addEvent,
- animObject = U.animObject,
- arrayMax = U.arrayMax,
- arrayMin = U.arrayMin,
- correctFloat = U.correctFloat,
- error = U.error,
- extend = U.extend,
- isArray = U.isArray,
- seriesType = U.seriesType;
- /* eslint-disable require-jsdoc */
- // Utils
- function arrayExtremesOHLC(data) {
- var dataLength = data.length,
- min = data[0][3],
- max = min,
- i = 1,
- currentPoint;
- for (; i < dataLength; i++) {
- currentPoint = data[i][3];
- if (currentPoint < min) {
- min = currentPoint;
- }
- if (currentPoint > max) {
- max = currentPoint;
- }
- }
- return {
- min: min,
- max: max
- };
- }
- /* eslint-enable require-jsdoc */
- var abs = Math.abs,
- noop = H.noop,
- columnPrototype = H.seriesTypes.column.prototype;
- /**
- * The Volume By Price (VBP) series type.
- *
- * @private
- * @class
- * @name Highcharts.seriesTypes.vbp
- *
- * @augments Highcharts.Series
- */
- seriesType('vbp', 'sma',
- /**
- * Volume By Price indicator.
- *
- * This series requires `linkedTo` option to be set.
- *
- * @sample stock/indicators/volume-by-price
- * Volume By Price indicator
- *
- * @extends plotOptions.sma
- * @since 6.0.0
- * @product highstock
- * @requires stock/indicators/indicators
- * @requires stock/indicators/volume-by-price
- * @optionparent plotOptions.vbp
- */
- {
- /**
- * @excluding index, period
- */
- params: {
- /**
- * The number of price zones.
- */
- ranges: 12,
- /**
- * The id of volume series which is mandatory. For example using
- * OHLC data, volumeSeriesID='volume' means the indicator will be
- * calculated using OHLC and volume values.
- */
- volumeSeriesID: 'volume'
- },
- /**
- * The styles for lines which determine price zones.
- */
- zoneLines: {
- /**
- * Enable/disable zone lines.
- */
- enabled: true,
- /**
- * Specify the style of zone lines.
- *
- * @type {Highcharts.CSSObject}
- * @default {"color": "#0A9AC9", "dashStyle": "LongDash", "lineWidth": 1}
- */
- styles: {
- /** @ignore-options */
- color: '#0A9AC9',
- /** @ignore-options */
- dashStyle: 'LongDash',
- /** @ignore-options */
- lineWidth: 1
- }
- },
- /**
- * The styles for bars when volume is divided into positive/negative.
- */
- volumeDivision: {
- /**
- * Option to control if volume is divided.
- */
- enabled: true,
- styles: {
- /**
- * Color of positive volume bars.
- *
- * @type {Highcharts.ColorString}
- */
- positiveColor: 'rgba(144, 237, 125, 0.8)',
- /**
- * Color of negative volume bars.
- *
- * @type {Highcharts.ColorString}
- */
- negativeColor: 'rgba(244, 91, 91, 0.8)'
- }
- },
- // To enable series animation; must be animationLimit > pointCount
- animationLimit: 1000,
- enableMouseTracking: false,
- pointPadding: 0,
- zIndex: -1,
- crisp: true,
- dataGrouping: {
- enabled: false
- },
- dataLabels: {
- allowOverlap: true,
- enabled: true,
- format: 'P: {point.volumePos:.2f} | N: {point.volumeNeg:.2f}',
- padding: 0,
- style: {
- /** @internal */
- fontSize: '7px'
- },
- verticalAlign: 'top'
- }
- },
- /**
- * @lends Highcharts.Series#
- */
- {
- nameBase: 'Volume by Price',
- bindTo: {
- series: false,
- eventName: 'afterSetExtremes'
- },
- calculateOn: 'render',
- markerAttribs: noop,
- drawGraph: noop,
- getColumnMetrics: columnPrototype.getColumnMetrics,
- crispCol: columnPrototype.crispCol,
- init: function (chart) {
- var indicator = this,
- params,
- baseSeries,
- volumeSeries;
- H.seriesTypes.sma.prototype.init.apply(indicator, arguments);
- params = indicator.options.params;
- baseSeries = indicator.linkedParent;
- volumeSeries = chart.get(params.volumeSeriesID);
- indicator.addCustomEvents(baseSeries, volumeSeries);
- return indicator;
- },
- // Adds events related with removing series
- addCustomEvents: function (baseSeries, volumeSeries) {
- var indicator = this;
- /* eslint-disable require-jsdoc */
- function toEmptyIndicator() {
- indicator.chart.redraw();
- indicator.setData([]);
- indicator.zoneStarts = [];
- if (indicator.zoneLinesSVG) {
- indicator.zoneLinesSVG.destroy();
- delete indicator.zoneLinesSVG;
- }
- }
- /* eslint-enable require-jsdoc */
- // If base series is deleted, indicator series data is filled with
- // an empty array
- indicator.dataEventsToUnbind.push(addEvent(baseSeries, 'remove', function () {
- toEmptyIndicator();
- }));
- // If volume series is deleted, indicator series data is filled with
- // an empty array
- if (volumeSeries) {
- indicator.dataEventsToUnbind.push(addEvent(volumeSeries, 'remove', function () {
- toEmptyIndicator();
- }));
- }
- return indicator;
- },
- // Initial animation
- animate: function (init) {
- var series = this,
- inverted = series.chart.inverted,
- group = series.group,
- attr = {},
- translate,
- position;
- if (!init && group) {
- translate = inverted ? 'translateY' : 'translateX';
- position = inverted ? series.yAxis.top : series.xAxis.left;
- group['forceAnimate:' + translate] = true;
- attr[translate] = position;
- group.animate(attr, extend(animObject(series.options.animation), {
- step: function (val, fx) {
- series.group.attr({
- scaleX: Math.max(0.001, fx.pos)
- });
- }
- }));
- }
- },
- drawPoints: function () {
- var indicator = this;
- if (indicator.options.volumeDivision.enabled) {
- indicator.posNegVolume(true, true);
- columnPrototype.drawPoints.apply(indicator, arguments);
- indicator.posNegVolume(false, false);
- }
- columnPrototype.drawPoints.apply(indicator, arguments);
- },
- // Function responsible for dividing volume into positive and negative
- posNegVolume: function (initVol, pos) {
- var indicator = this, signOrder = pos ?
- ['positive', 'negative'] :
- ['negative', 'positive'], volumeDivision = indicator.options.volumeDivision, pointLength = indicator.points.length, posWidths = [], negWidths = [], i = 0, pointWidth, priceZone, wholeVol, point;
- if (initVol) {
- indicator.posWidths = posWidths;
- indicator.negWidths = negWidths;
- }
- else {
- posWidths = indicator.posWidths;
- negWidths = indicator.negWidths;
- }
- for (; i < pointLength; i++) {
- point = indicator.points[i];
- point[signOrder[0] + 'Graphic'] = point.graphic;
- point.graphic = point[signOrder[1] + 'Graphic'];
- if (initVol) {
- pointWidth = point.shapeArgs.width;
- priceZone = indicator.priceZones[i];
- wholeVol = priceZone.wholeVolumeData;
- if (wholeVol) {
- posWidths.push(pointWidth / wholeVol * priceZone.positiveVolumeData);
- negWidths.push(pointWidth / wholeVol * priceZone.negativeVolumeData);
- }
- else {
- posWidths.push(0);
- negWidths.push(0);
- }
- }
- point.color = pos ?
- volumeDivision.styles.positiveColor :
- volumeDivision.styles.negativeColor;
- point.shapeArgs.width = pos ?
- indicator.posWidths[i] :
- indicator.negWidths[i];
- point.shapeArgs.x = pos ?
- point.shapeArgs.x :
- indicator.posWidths[i];
- }
- },
- translate: function () {
- var indicator = this,
- options = indicator.options,
- chart = indicator.chart,
- yAxis = indicator.yAxis,
- yAxisMin = yAxis.min,
- zoneLinesOptions = indicator.options.zoneLines,
- priceZones = (indicator.priceZones),
- yBarOffset = 0,
- indicatorPoints,
- volumeDataArray,
- maxVolume,
- primalBarWidth,
- barHeight,
- barHeightP,
- oldBarHeight,
- barWidth,
- pointPadding,
- chartPlotTop,
- barX,
- barY;
- columnPrototype.translate.apply(indicator);
- indicatorPoints = indicator.points;
- // Do translate operation when points exist
- if (indicatorPoints.length) {
- pointPadding = options.pointPadding < 0.5 ?
- options.pointPadding :
- 0.1;
- volumeDataArray = indicator.volumeDataArray;
- maxVolume = arrayMax(volumeDataArray);
- primalBarWidth = chart.plotWidth / 2;
- chartPlotTop = chart.plotTop;
- barHeight = abs(yAxis.toPixels(yAxisMin) -
- yAxis.toPixels(yAxisMin + indicator.rangeStep));
- oldBarHeight = abs(yAxis.toPixels(yAxisMin) -
- yAxis.toPixels(yAxisMin + indicator.rangeStep));
- if (pointPadding) {
- barHeightP = abs(barHeight * (1 - 2 * pointPadding));
- yBarOffset = abs((barHeight - barHeightP) / 2);
- barHeight = abs(barHeightP);
- }
- indicatorPoints.forEach(function (point, index) {
- barX = point.barX = point.plotX = 0;
- barY = point.plotY = (yAxis.toPixels(priceZones[index].start) -
- chartPlotTop -
- (yAxis.reversed ?
- (barHeight - oldBarHeight) :
- barHeight) -
- yBarOffset);
- barWidth = correctFloat(primalBarWidth *
- priceZones[index].wholeVolumeData / maxVolume);
- point.pointWidth = barWidth;
- point.shapeArgs = indicator.crispCol.apply(// eslint-disable-line no-useless-call
- indicator, [barX, barY, barWidth, barHeight]);
- point.volumeNeg = priceZones[index].negativeVolumeData;
- point.volumePos = priceZones[index].positiveVolumeData;
- point.volumeAll = priceZones[index].wholeVolumeData;
- });
- if (zoneLinesOptions.enabled) {
- indicator.drawZones(chart, yAxis, indicator.zoneStarts, zoneLinesOptions.styles);
- }
- }
- },
- getValues: function (series, params) {
- var indicator = this,
- xValues = series.processedXData,
- yValues = series.processedYData,
- chart = indicator.chart,
- ranges = params.ranges,
- VBP = [],
- xData = [],
- yData = [],
- isOHLC,
- volumeSeries,
- priceZones;
- // Checks if base series exists
- if (!series.chart) {
- error('Base series not found! In case it has been removed, add ' +
- 'a new one.', true, chart);
- return;
- }
- // Checks if volume series exists
- if (!(volumeSeries = (chart.get(params.volumeSeriesID)))) {
- error('Series ' +
- params.volumeSeriesID +
- ' not found! Check `volumeSeriesID`.', true, chart);
- return;
- }
- // Checks if series data fits the OHLC format
- isOHLC = isArray(yValues[0]);
- if (isOHLC && yValues[0].length !== 4) {
- error('Type of ' +
- series.name +
- ' series is different than line, OHLC or candlestick.', true, chart);
- return;
- }
- // Price zones contains all the information about the zones (index,
- // start, end, volumes, etc.)
- priceZones = indicator.priceZones = indicator.specifyZones(isOHLC, xValues, yValues, ranges, volumeSeries);
- priceZones.forEach(function (zone, index) {
- VBP.push([zone.x, zone.end]);
- xData.push(VBP[index][0]);
- yData.push(VBP[index][1]);
- });
- return {
- values: VBP,
- xData: xData,
- yData: yData
- };
- },
- // Specifing where each zone should start ans end
- specifyZones: function (isOHLC, xValues, yValues, ranges, volumeSeries) {
- var indicator = this,
- rangeExtremes = (isOHLC ? arrayExtremesOHLC(yValues) : false),
- lowRange = rangeExtremes ?
- rangeExtremes.min :
- arrayMin(yValues),
- highRange = rangeExtremes ?
- rangeExtremes.max :
- arrayMax(yValues),
- zoneStarts = indicator.zoneStarts = [],
- priceZones = [],
- i = 0,
- j = 1,
- rangeStep,
- zoneStartsLength;
- if (!lowRange || !highRange) {
- if (this.points.length) {
- this.setData([]);
- this.zoneStarts = [];
- this.zoneLinesSVG.destroy();
- }
- return [];
- }
- rangeStep = indicator.rangeStep =
- correctFloat(highRange - lowRange) / ranges;
- zoneStarts.push(lowRange);
- for (; i < ranges - 1; i++) {
- zoneStarts.push(correctFloat(zoneStarts[i] + rangeStep));
- }
- zoneStarts.push(highRange);
- zoneStartsLength = zoneStarts.length;
- // Creating zones
- for (; j < zoneStartsLength; j++) {
- priceZones.push({
- index: j - 1,
- x: xValues[0],
- start: zoneStarts[j - 1],
- end: zoneStarts[j]
- });
- }
- return indicator.volumePerZone(isOHLC, priceZones, volumeSeries, xValues, yValues);
- },
- // Calculating sum of volume values for a specific zone
- volumePerZone: function (isOHLC, priceZones, volumeSeries, xValues, yValues) {
- var indicator = this,
- volumeXData = volumeSeries.processedXData,
- volumeYData = volumeSeries.processedYData,
- lastZoneIndex = priceZones.length - 1,
- baseSeriesLength = yValues.length,
- volumeSeriesLength = volumeYData.length,
- previousValue,
- startFlag,
- endFlag,
- value,
- i;
- // Checks if each point has a corresponding volume value
- if (abs(baseSeriesLength - volumeSeriesLength)) {
- // If the first point don't have volume, add 0 value at the
- // beggining of the volume array
- if (xValues[0] !== volumeXData[0]) {
- volumeYData.unshift(0);
- }
- // If the last point don't have volume, add 0 value at the end
- // of the volume array
- if (xValues[baseSeriesLength - 1] !==
- volumeXData[volumeSeriesLength - 1]) {
- volumeYData.push(0);
- }
- }
- indicator.volumeDataArray = [];
- priceZones.forEach(function (zone) {
- zone.wholeVolumeData = 0;
- zone.positiveVolumeData = 0;
- zone.negativeVolumeData = 0;
- for (i = 0; i < baseSeriesLength; i++) {
- startFlag = false;
- endFlag = false;
- value = isOHLC ? yValues[i][3] : yValues[i];
- previousValue = i ?
- (isOHLC ?
- yValues[i - 1][3] :
- yValues[i - 1]) :
- value;
- // Checks if this is the point with the
- // lowest close value and if so, adds it calculations
- if (value <= zone.start && zone.index === 0) {
- startFlag = true;
- }
- // Checks if this is the point with the highest
- // close value and if so, adds it calculations
- if (value >= zone.end && zone.index === lastZoneIndex) {
- endFlag = true;
- }
- if ((value > zone.start || startFlag) &&
- (value < zone.end || endFlag)) {
- zone.wholeVolumeData += volumeYData[i];
- if (previousValue > value) {
- zone.negativeVolumeData += volumeYData[i];
- }
- else {
- zone.positiveVolumeData += volumeYData[i];
- }
- }
- }
- indicator.volumeDataArray.push(zone.wholeVolumeData);
- });
- return priceZones;
- },
- // Function responsoble for drawing additional lines indicating zones
- drawZones: function (chart, yAxis, zonesValues, zonesStyles) {
- var indicator = this,
- renderer = chart.renderer,
- zoneLinesSVG = indicator.zoneLinesSVG,
- zoneLinesPath = [],
- leftLinePos = 0,
- rightLinePos = chart.plotWidth,
- verticalOffset = chart.plotTop,
- verticalLinePos;
- zonesValues.forEach(function (value) {
- verticalLinePos = yAxis.toPixels(value) - verticalOffset;
- zoneLinesPath = zoneLinesPath.concat(chart.renderer.crispLine([[
- 'M',
- leftLinePos,
- verticalLinePos
- ], [
- 'L',
- rightLinePos,
- verticalLinePos
- ]], zonesStyles.lineWidth));
- });
- // Create zone lines one path or update it while animating
- if (zoneLinesSVG) {
- zoneLinesSVG.animate({
- d: zoneLinesPath
- });
- }
- else {
- zoneLinesSVG = indicator.zoneLinesSVG =
- renderer.path(zoneLinesPath).attr({
- 'stroke-width': zonesStyles.lineWidth,
- 'stroke': zonesStyles.color,
- 'dashstyle': zonesStyles.dashStyle,
- 'zIndex': indicator.group.zIndex + 0.1
- })
- .add(indicator.group);
- }
- }
- },
- /**
- * @lends Highcharts.Point#
- */
- {
- // Required for destroying negative part of volume
- destroy: function () {
- // @todo: this.negativeGraphic doesn't seem to be used anywhere
- if (this.negativeGraphic) {
- this.negativeGraphic = this.negativeGraphic.destroy();
- }
- return Point.prototype.destroy.apply(this, arguments);
- }
- });
- /**
- * A `Volume By Price (VBP)` series. If the [type](#series.vbp.type) option is
- * not specified, it is inherited from [chart.type](#chart.type).
- *
- * @extends series,plotOptions.vbp
- * @since 6.0.0
- * @product highstock
- * @excluding dataParser, dataURL
- * @requires stock/indicators/indicators
- * @requires stock/indicators/volume-by-price
- * @apioption series.vbp
- */
- ''; // to include the above in the js output
- });
- _registerModule(_modules, 'Stock/Indicators/VWAPIndicator.js', [_modules['Core/Utilities.js']], function (U) {
- /* *
- *
- * (c) 2010-2020 Paweł Dalek
- *
- * Volume Weighted Average Price (VWAP) indicator for Highstock
- *
- * License: www.highcharts.com/license
- *
- * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
- *
- * */
- var error = U.error,
- isArray = U.isArray,
- seriesType = U.seriesType;
- /**
- * The Volume Weighted Average Price (VWAP) series type.
- *
- * @private
- * @class
- * @name Highcharts.seriesTypes.vwap
- *
- * @augments Highcharts.Series
- */
- seriesType('vwap', 'sma',
- /**
- * Volume Weighted Average Price indicator.
- *
- * This series requires `linkedTo` option to be set.
- *
- * @sample stock/indicators/vwap
- * Volume Weighted Average Price indicator
- *
- * @extends plotOptions.sma
- * @since 6.0.0
- * @product highstock
- * @requires stock/indicators/indicators
- * @requires stock/indicators/vwap
- * @optionparent plotOptions.vwap
- */
- {
- /**
- * @excluding index
- */
- params: {
- period: 30,
- /**
- * The id of volume series which is mandatory. For example using
- * OHLC data, volumeSeriesID='volume' means the indicator will be
- * calculated using OHLC and volume values.
- */
- volumeSeriesID: 'volume'
- }
- },
- /**
- * @lends Highcharts.Series#
- */
- {
- /**
- * Returns the final values of the indicator ready to be presented on a
- * chart
- * @private
- * @param {Highcharts.VWAPIndicator} this indicator
- * @param {Highcharts.Series} series - series for indicator
- * @param {object} params - params
- * @return {object} - computed VWAP
- **/
- getValues: function (series, params) {
- var indicator = this,
- chart = series.chart,
- xValues = series.xData,
- yValues = series.yData,
- period = params.period,
- isOHLC = true,
- volumeSeries;
- // Checks if volume series exists
- if (!(volumeSeries = (chart.get(params.volumeSeriesID)))) {
- error('Series ' +
- params.volumeSeriesID +
- ' not found! Check `volumeSeriesID`.', true, chart);
- return;
- }
- // Checks if series data fits the OHLC format
- if (!(isArray(yValues[0]))) {
- isOHLC = false;
- }
- return indicator.calculateVWAPValues(isOHLC, xValues, yValues, volumeSeries, period);
- },
- /**
- * Main algorithm used to calculate Volume Weighted Average Price (VWAP)
- * values
- * @private
- * @param {boolean} isOHLC - says if data has OHLC format
- * @param {Array<number>} xValues - array of timestamps
- * @param {Array<number|Array<number,number,number,number>>} yValues -
- * array of yValues, can be an array of a four arrays (OHLC) or array of
- * values (line)
- * @param {Array<*>} volumeSeries - volume series
- * @param {number} period - number of points to be calculated
- * @return {object} - Object contains computed VWAP
- **/
- calculateVWAPValues: function (isOHLC, xValues, yValues, volumeSeries, period) {
- var volumeValues = volumeSeries.yData,
- volumeLength = volumeSeries.xData.length,
- pointsLength = xValues.length,
- cumulativePrice = [],
- cumulativeVolume = [],
- xData = [],
- yData = [],
- VWAP = [],
- commonLength,
- typicalPrice,
- cPrice,
- cVolume,
- i,
- j;
- if (pointsLength <= volumeLength) {
- commonLength = pointsLength;
- }
- else {
- commonLength = volumeLength;
- }
- for (i = 0, j = 0; i < commonLength; i++) {
- // Depending on whether series is OHLC or line type, price is
- // average of the high, low and close or a simple value
- typicalPrice = isOHLC ?
- ((yValues[i][1] + yValues[i][2] +
- yValues[i][3]) / 3) :
- yValues[i];
- typicalPrice *= volumeValues[i];
- cPrice = j ?
- (cumulativePrice[i - 1] + typicalPrice) :
- typicalPrice;
- cVolume = j ?
- (cumulativeVolume[i - 1] + volumeValues[i]) :
- volumeValues[i];
- cumulativePrice.push(cPrice);
- cumulativeVolume.push(cVolume);
- VWAP.push([xValues[i], (cPrice / cVolume)]);
- xData.push(VWAP[i][0]);
- yData.push(VWAP[i][1]);
- j++;
- if (j === period) {
- j = 0;
- }
- }
- return {
- values: VWAP,
- xData: xData,
- yData: yData
- };
- }
- });
- /**
- * A `Volume Weighted Average Price (VWAP)` series. If the
- * [type](#series.vwap.type) option is not specified, it is inherited from
- * [chart.type](#chart.type).
- *
- * @extends series,plotOptions.vwap
- * @since 6.0.0
- * @product highstock
- * @excluding dataParser, dataURL
- * @requires stock/indicators/indicators
- * @requires stock/indicators/vwap
- * @apioption series.vwap
- */
- ''; // to include the above in the js output
- });
- _registerModule(_modules, 'Stock/Indicators/WilliamsRIndicator.js', [_modules['Core/Utilities.js'], _modules['Mixins/ReduceArray.js']], function (U, reduceArrayMixin) {
- /* *
- *
- * License: www.highcharts.com/license
- *
- * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
- *
- * */
- var isArray = U.isArray,
- seriesType = U.seriesType;
- var getArrayExtremes = reduceArrayMixin.getArrayExtremes;
- /**
- * The Williams %R series type.
- *
- * @private
- * @class
- * @name Highcharts.seriesTypes.williamsr
- *
- * @augments Highcharts.Series
- */
- seriesType('williamsr', 'sma',
- /**
- * Williams %R. This series requires the `linkedTo` option to be
- * set and should be loaded after the `stock/indicators/indicators.js`.
- *
- * @sample {highstock} stock/indicators/williams-r
- * Williams %R
- *
- * @extends plotOptions.sma
- * @since 7.0.0
- * @product highstock
- * @excluding allAreas, colorAxis, joinBy, keys, navigatorOptions,
- * pointInterval, pointIntervalUnit, pointPlacement,
- * pointRange, pointStart, showInNavigator, stacking
- * @requires stock/indicators/indicators
- * @requires stock/indicators/williams-r
- * @optionparent plotOptions.williamsr
- */
- {
- /**
- * Paramters used in calculation of Williams %R series points.
- * @excluding index
- */
- params: {
- /**
- * Period for Williams %R oscillator
- */
- period: 14
- }
- },
- /**
- * @lends Highcharts.Series#
- */
- {
- nameBase: 'Williams %R',
- getValues: function (series, params) {
- var period = params.period,
- xVal = series.xData,
- yVal = series.yData,
- yValLen = yVal ? yVal.length : 0,
- WR = [], // 0- date, 1- Williams %R
- xData = [],
- yData = [],
- slicedY,
- close = 3,
- low = 2,
- high = 1,
- extremes,
- R,
- HH, // Highest high value in period
- LL, // Lowest low value in period
- CC, // Current close value
- i;
- // Williams %R requires close value
- if (xVal.length < period ||
- !isArray(yVal[0]) ||
- yVal[0].length !== 4) {
- return;
- }
- // For a N-period, we start from N-1 point, to calculate Nth point
- // That is why we later need to comprehend slice() elements list
- // with (+1)
- for (i = period - 1; i < yValLen; i++) {
- slicedY = yVal.slice(i - period + 1, i + 1);
- extremes = getArrayExtremes(slicedY, low, high);
- LL = extremes[0];
- HH = extremes[1];
- CC = yVal[i][close];
- R = ((HH - CC) / (HH - LL)) * -100;
- if (xVal[i]) {
- WR.push([xVal[i], R]);
- xData.push(xVal[i]);
- yData.push(R);
- }
- }
- return {
- values: WR,
- xData: xData,
- yData: yData
- };
- }
- });
- /**
- * A `Williams %R Oscillator` series. If the [type](#series.williamsr.type)
- * option is not specified, it is inherited from [chart.type](#chart.type).
- *
- * @extends series,plotOptions.williamsr
- * @since 7.0.0
- * @product highstock
- * @excluding allAreas, colorAxis, dataParser, dataURL, joinBy, keys,
- * navigatorOptions, pointInterval, pointIntervalUnit,
- * pointPlacement, pointRange, pointStart, showInNavigator, stacking
- * @requires stock/indicators/indicators
- * @requires stock/indicators/williams-r
- * @apioption series.williamsr
- */
- ''; // adds doclets above to the transpiled file
- });
- _registerModule(_modules, 'Stock/Indicators/WMAIndicator.js', [_modules['Core/Utilities.js']], function (U) {
- /* *
- *
- * (c) 2010-2020 Kacper Madej
- *
- * License: www.highcharts.com/license
- *
- * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
- *
- * */
- var isArray = U.isArray,
- seriesType = U.seriesType;
- /* eslint-disable valid-jsdoc */
- // Utils:
- /**
- * @private
- */
- function accumulateAverage(points, xVal, yVal, i, index) {
- var xValue = xVal[i],
- yValue = index < 0 ? yVal[i] : yVal[i][index];
- points.push([xValue, yValue]);
- }
- /**
- * @private
- */
- function weightedSumArray(array, pLen) {
- // The denominator is the sum of the number of days as a triangular number.
- // If there are 5 days, the triangular numbers are 5, 4, 3, 2, and 1.
- // The sum is 5 + 4 + 3 + 2 + 1 = 15.
- var denominator = (pLen + 1) / 2 * pLen;
- // reduce VS loop => reduce
- return array.reduce(function (prev, cur, i) {
- return [null, prev[1] + cur[1] * (i + 1)];
- })[1] / denominator;
- }
- /**
- * @private
- */
- function populateAverage(points, xVal, yVal, i) {
- var pLen = points.length,
- wmaY = weightedSumArray(points,
- pLen),
- wmaX = xVal[i - 1];
- points.shift(); // remove point until range < period
- return [wmaX, wmaY];
- }
- /* eslint-enable valid-jsdoc */
- /**
- * The SMA series type.
- *
- * @private
- * @class
- * @name Highcharts.seriesTypes.wma
- *
- * @augments Highcharts.Series
- */
- seriesType('wma', 'sma',
- /**
- * Weighted moving average indicator (WMA). This series requires `linkedTo`
- * option to be set.
- *
- * @sample stock/indicators/wma
- * Weighted moving average indicator
- *
- * @extends plotOptions.sma
- * @since 6.0.0
- * @product highstock
- * @requires stock/indicators/indicators
- * @requires stock/indicators/wma
- * @optionparent plotOptions.wma
- */
- {
- params: {
- index: 3,
- period: 9
- }
- },
- /**
- * @lends Highcharts.Series#
- */
- {
- getValues: function (series, params) {
- var period = params.period,
- xVal = series.xData,
- yVal = series.yData,
- yValLen = yVal ? yVal.length : 0,
- range = 1,
- xValue = xVal[0],
- yValue = yVal[0],
- WMA = [],
- xData = [],
- yData = [],
- index = -1,
- i,
- points,
- WMAPoint;
- if (xVal.length < period) {
- return;
- }
- // Switch index for OHLC / Candlestick
- if (isArray(yVal[0])) {
- index = params.index;
- yValue = yVal[0][index];
- }
- // Starting point
- points = [[xValue, yValue]];
- // Accumulate first N-points
- while (range !== period) {
- accumulateAverage(points, xVal, yVal, range, index);
- range++;
- }
- // Calculate value one-by-one for each period in visible data
- for (i = range; i < yValLen; i++) {
- WMAPoint = populateAverage(points, xVal, yVal, i);
- WMA.push(WMAPoint);
- xData.push(WMAPoint[0]);
- yData.push(WMAPoint[1]);
- accumulateAverage(points, xVal, yVal, i, index);
- }
- WMAPoint = populateAverage(points, xVal, yVal, i);
- WMA.push(WMAPoint);
- xData.push(WMAPoint[0]);
- yData.push(WMAPoint[1]);
- return {
- values: WMA,
- xData: xData,
- yData: yData
- };
- }
- });
- /**
- * A `WMA` series. If the [type](#series.wma.type) option is not specified, it
- * is inherited from [chart.type](#chart.type).
- *
- * @extends series,plotOptions.wma
- * @since 6.0.0
- * @product highstock
- * @excluding dataParser, dataURL
- * @requires stock/indicators/indicators
- * @requires stock/indicators/wma
- * @apioption series.wma
- */
- ''; // adds doclet above to the transpiled file
- });
- _registerModule(_modules, 'Stock/Indicators/ZigzagIndicator.js', [_modules['Core/Utilities.js']], function (U) {
- /* *
- *
- * (c) 2010-2020 Kacper Madej
- *
- * License: www.highcharts.com/license
- *
- * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
- *
- * */
- var seriesType = U.seriesType;
- var UNDEFINED;
- /**
- * The Zig Zag series type.
- *
- * @private
- * @class
- * @name Highcharts.seriesTypes.zigzag
- *
- * @augments Highcharts.Series
- */
- seriesType('zigzag', 'sma',
- /**
- * Zig Zag indicator.
- *
- * This series requires `linkedTo` option to be set.
- *
- * @sample stock/indicators/zigzag
- * Zig Zag indicator
- *
- * @extends plotOptions.sma
- * @since 6.0.0
- * @product highstock
- * @requires stock/indicators/indicators
- * @requires stock/indicators/zigzag
- * @optionparent plotOptions.zigzag
- */
- {
- /**
- * @excluding index, period
- */
- params: {
- /**
- * The point index which indicator calculations will base - low
- * value.
- *
- * For example using OHLC data, index=2 means the indicator will be
- * calculated using Low values.
- */
- lowIndex: 2,
- /**
- * The point index which indicator calculations will base - high
- * value.
- *
- * For example using OHLC data, index=1 means the indicator will be
- * calculated using High values.
- */
- highIndex: 1,
- /**
- * The threshold for the value change.
- *
- * For example deviation=1 means the indicator will ignore all price
- * movements less than 1%.
- */
- deviation: 1
- }
- },
- /**
- * @lends Highcharts.Series#
- */
- {
- nameComponents: ['deviation'],
- nameSuffixes: ['%'],
- nameBase: 'Zig Zag',
- getValues: function (series, params) {
- var lowIndex = params.lowIndex,
- highIndex = params.highIndex,
- deviation = params.deviation / 100,
- deviations = {
- 'low': 1 + deviation,
- 'high': 1 - deviation
- },
- xVal = series.xData,
- yVal = series.yData,
- yValLen = yVal ? yVal.length : 0,
- zigzag = [],
- xData = [],
- yData = [],
- i,
- j,
- zigzagPoint,
- firstZigzagLow,
- firstZigzagHigh,
- directionUp,
- zigzagLen,
- exitLoop = false,
- yIndex = false;
- // Exit if not enught points or no low or high values
- if (!xVal || xVal.length <= 1 ||
- (yValLen &&
- (yVal[0][lowIndex] === UNDEFINED ||
- yVal[0][highIndex] === UNDEFINED))) {
- return;
- }
- // Set first zigzag point candidate
- firstZigzagLow = yVal[0][lowIndex];
- firstZigzagHigh = yVal[0][highIndex];
- // Search for a second zigzag point candidate,
- // this will also set first zigzag point
- for (i = 1; i < yValLen; i++) {
- // requried change to go down
- if (yVal[i][lowIndex] <= firstZigzagHigh * deviations.high) {
- zigzag.push([xVal[0], firstZigzagHigh]);
- // second zigzag point candidate
- zigzagPoint = [xVal[i], yVal[i][lowIndex]];
- // next line will be going up
- directionUp = true;
- exitLoop = true;
- // requried change to go up
- }
- else if (yVal[i][highIndex] >= firstZigzagLow * deviations.low) {
- zigzag.push([xVal[0], firstZigzagLow]);
- // second zigzag point candidate
- zigzagPoint = [xVal[i], yVal[i][highIndex]];
- // next line will be going down
- directionUp = false;
- exitLoop = true;
- }
- if (exitLoop) {
- xData.push(zigzag[0][0]);
- yData.push(zigzag[0][1]);
- j = i++;
- i = yValLen;
- }
- }
- // Search for next zigzags
- for (i = j; i < yValLen; i++) {
- if (directionUp) { // next line up
- // lower when going down -> change zigzag candidate
- if (yVal[i][lowIndex] <= zigzagPoint[1]) {
- zigzagPoint = [xVal[i], yVal[i][lowIndex]];
- }
- // requried change to go down -> new zigzagpoint and
- // direction change
- if (yVal[i][highIndex] >=
- zigzagPoint[1] * deviations.low) {
- yIndex = highIndex;
- }
- }
- else { // next line down
- // higher when going up -> change zigzag candidate
- if (yVal[i][highIndex] >= zigzagPoint[1]) {
- zigzagPoint = [xVal[i], yVal[i][highIndex]];
- }
- // requried change to go down -> new zigzagpoint and
- // direction change
- if (yVal[i][lowIndex] <=
- zigzagPoint[1] * deviations.high) {
- yIndex = lowIndex;
- }
- }
- if (yIndex !== false) { // new zigzag point and direction change
- zigzag.push(zigzagPoint);
- xData.push(zigzagPoint[0]);
- yData.push(zigzagPoint[1]);
- zigzagPoint = [xVal[i], yVal[i][yIndex]];
- directionUp = !directionUp;
- yIndex = false;
- }
- }
- zigzagLen = zigzag.length;
- // no zigzag for last point
- if (zigzagLen !== 0 &&
- zigzag[zigzagLen - 1][0] < xVal[yValLen - 1]) {
- // set last point from zigzag candidate
- zigzag.push(zigzagPoint);
- xData.push(zigzagPoint[0]);
- yData.push(zigzagPoint[1]);
- }
- return {
- values: zigzag,
- xData: xData,
- yData: yData
- };
- }
- });
- /**
- * A `Zig Zag` series. If the [type](#series.zigzag.type) option is not
- * specified, it is inherited from [chart.type](#chart.type).
- *
- * @extends series,plotOptions.zigzag
- * @since 6.0.0
- * @product highstock
- * @excluding dataParser, dataURL
- * @requires stock/indicators/indicators
- * @requires stock/indicators/zigzag
- * @apioption series.zigzag
- */
- ''; // adds doclets above to transpiled file
- });
- _registerModule(_modules, 'Stock/Indicators/RegressionIndicators.js', [_modules['Core/Utilities.js']], function (U) {
- /**
- *
- * (c) 2010-2020 Kamil Kulig
- *
- * License: www.highcharts.com/license
- *
- * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
- *
- * */
- var isArray = U.isArray,
- seriesType = U.seriesType;
- /**
- * Linear regression series type.
- *
- * @private
- * @class
- * @name Highcharts.seriesTypes.linearregression
- *
- * @augments Highcharts.Series
- */
- seriesType('linearRegression', 'sma',
- /**
- * Linear regression indicator. This series requires `linkedTo` option to be
- * set.
- *
- * @sample {highstock} stock/indicators/linear-regression
- * Linear regression indicator
- *
- * @extends plotOptions.sma
- * @since 7.0.0
- * @product highstock
- * @requires stock/indicators/indicators
- * @requires stock/indicators/regressions
- * @optionparent plotOptions.linearregression
- */
- {
- params: {
- /**
- * Unit (in milliseconds) for the x axis distances used to compute
- * the regression line paramters (slope & intercept) for every
- * range. In Highstock the x axis values are always represented in
- * milliseconds which may cause that distances between points are
- * "big" integer numbers.
- *
- * Highstock's linear regression algorithm (least squares method)
- * will utilize these "big" integers for finding the slope and the
- * intercept of the regression line for each period. In consequence,
- * this value may be a very "small" decimal number that's hard to
- * interpret by a human.
- *
- * For instance: `xAxisUnit` equealed to `86400000` ms (1 day)
- * forces the algorithm to treat `86400000` as `1` while computing
- * the slope and the intercept. This may enchance the legiblitity of
- * the indicator's values.
- *
- * Default value is the closest distance between two data points.
- *
- * @sample {highstock} stock/plotoptions/linear-regression-xaxisunit
- * xAxisUnit set to 1 minute
- *
- * @example
- * // In Liniear Regression Slope Indicator series `xAxisUnit` is
- * // `86400000` (1 day) and period is `3`. There're 3 points in the
- * // base series:
- *
- * data: [
- * [Date.UTC(2020, 0, 1), 1],
- * [Date.UTC(2020, 0, 2), 3],
- * [Date.UTC(2020, 0, 3), 5]
- * ]
- *
- * // This will produce one point in the indicator series that has a
- * // `y` value of `2` (slope of the regression line). If we change
- * // the `xAxisUnit` to `1` (ms) the value of the indicator's point
- * // will be `2.3148148148148148e-8` which is harder to interpert
- * // for a human.
- *
- * @type {number}
- * @product highstock
- */
- xAxisUnit: void 0
- },
- tooltip: {
- valueDecimals: 4
- }
- },
- /**
- * @lends Highcharts.Series#
- */
- {
- nameBase: 'Linear Regression Indicator',
- /**
- * Return the slope and intercept of a straight line function.
- * @private
- * @param {Highcharts.LinearRegressionIndicator} this indicator to use
- * @param {Array<number>} xData - list of all x coordinates in a period
- * @param {Array<number>} yData - list of all y coordinates in a period
- * @return {Highcharts.RegressionLineParametersObject}
- * object that contains the slope and the intercept
- * of a straight line function
- */
- getRegressionLineParameters: function (xData, yData) {
- // least squares method
- var yIndex = this.options.params.index,
- getSingleYValue = function (yValue,
- yIndex) {
- return isArray(yValue) ? yValue[yIndex] : yValue;
- }, xSum = xData.reduce(function (accX, val) {
- return val + accX;
- }, 0), ySum = yData.reduce(function (accY, val) {
- return getSingleYValue(val, yIndex) + accY;
- }, 0), xMean = xSum / xData.length, yMean = ySum / yData.length, xError, yError, formulaNumerator = 0, formulaDenominator = 0, i, slope;
- for (i = 0; i < xData.length; i++) {
- xError = xData[i] - xMean;
- yError = getSingleYValue(yData[i], yIndex) - yMean;
- formulaNumerator += xError * yError;
- formulaDenominator += Math.pow(xError, 2);
- }
- slope = formulaDenominator ?
- formulaNumerator / formulaDenominator : 0; // don't divide by 0
- return {
- slope: slope,
- intercept: yMean - slope * xMean
- };
- },
- /**
- * Return the y value on a straight line.
- * @private
- * @param {Highcharts.RegressionLineParametersObject} lineParameters
- * object that contains the slope and the intercept
- * of a straight line function
- * @param {number} endPointX - x coordinate of the point
- * @return {number} - y value of the point that lies on the line
- */
- getEndPointY: function (lineParameters, endPointX) {
- return lineParameters.slope * endPointX + lineParameters.intercept;
- },
- /**
- * Transform the coordinate system so that x values start at 0 and
- * apply xAxisUnit.
- * @private
- * @param {Array<number>} xData - list of all x coordinates in a period
- * @param {number} xAxisUnit - option (see the API)
- * @return {Array<number>} - array of transformed x data
- */
- transformXData: function (xData, xAxisUnit) {
- var xOffset = xData[0];
- return xData.map(function (xValue) {
- return (xValue - xOffset) / xAxisUnit;
- });
- },
- /**
- * Find the closest distance between points in the base series.
- * @private
- * @param {Array<number>} xData
- list of all x coordinates in the base series
- * @return {number} - closest distance between points in the base series
- */
- findClosestDistance: function (xData) {
- var distance,
- closestDistance,
- i;
- for (i = 1; i < xData.length - 1; i++) {
- distance = xData[i] - xData[i - 1];
- if (distance > 0 &&
- (typeof closestDistance === 'undefined' ||
- distance < closestDistance)) {
- closestDistance = distance;
- }
- }
- return closestDistance;
- },
- // Required to be implemented - starting point for indicator's logic
- getValues: function (baseSeries, regressionSeriesParams) {
- var xData = baseSeries.xData,
- yData = baseSeries.yData,
- period = regressionSeriesParams.period,
- lineParameters,
- i,
- periodStart,
- periodEnd,
- // format required to be returned
- indicatorData = {
- xData: [],
- yData: [],
- values: []
- },
- endPointX,
- endPointY,
- periodXData,
- periodYData,
- periodTransformedXData,
- xAxisUnit = this.options.params.xAxisUnit ||
- this.findClosestDistance(xData);
- // Iteration logic: x value of the last point within the period
- // (end point) is used to represent the y value (regression)
- // of the entire period.
- for (i = period - 1; i <= xData.length - 1; i++) {
- periodStart = i - period + 1; // adjusted for slice() function
- periodEnd = i + 1; // (as above)
- endPointX = xData[i];
- periodXData = xData.slice(periodStart, periodEnd);
- periodYData = yData.slice(periodStart, periodEnd);
- periodTransformedXData = this.transformXData(periodXData, xAxisUnit);
- lineParameters = this.getRegressionLineParameters(periodTransformedXData, periodYData);
- endPointY = this.getEndPointY(lineParameters, periodTransformedXData[periodTransformedXData.length - 1]);
- // @todo this is probably not used anywhere
- indicatorData.values.push({
- regressionLineParameters: lineParameters,
- x: endPointX,
- y: endPointY
- });
- indicatorData.xData.push(endPointX);
- indicatorData.yData.push(endPointY);
- }
- return indicatorData;
- }
- });
- /**
- * A linear regression series. If the [type](#series.linearregression.type)
- * option is not specified, it is inherited from [chart.type](#chart.type).
- *
- * @extends series,plotOptions.linearregression
- * @since 7.0.0
- * @product highstock
- * @excluding dataParser,dataURL
- * @requires stock/indicators/indicators
- * @requires stock/indicators/regressions
- * @apioption series.linearregression
- */
- /* ************************************************************************** */
- /**
- * The Linear Regression Slope series type.
- *
- * @private
- * @class
- * @name Highcharts.seriesTypes.linearRegressionSlope
- *
- * @augments Highcharts.Series
- */
- seriesType('linearRegressionSlope', 'linearRegression',
- /**
- * Linear regression slope indicator. This series requires `linkedTo`
- * option to be set.
- *
- * @sample {highstock} stock/indicators/linear-regression-slope
- * Linear regression slope indicator
- *
- * @extends plotOptions.linearregression
- * @since 7.0.0
- * @product highstock
- * @requires stock/indicators/indicators
- * @requires stock/indicators/regressions
- * @optionparent plotOptions.linearregressionslope
- */
- {},
- /**
- * @lends Highcharts.Series#
- */
- {
- nameBase: 'Linear Regression Slope Indicator',
- getEndPointY: function (lineParameters) {
- return lineParameters.slope;
- }
- });
- /**
- * A linear regression slope series. If the
- * [type](#series.linearregressionslope.type) option is not specified, it is
- * inherited from [chart.type](#chart.type).
- *
- * @extends series,plotOptions.linearregressionslope
- * @since 7.0.0
- * @product highstock
- * @excluding dataParser,dataURL
- * @requires stock/indicators/indicators
- * @requires stock/indicators/regressions
- * @apioption series.linearregressionslope
- */
- /* ************************************************************************** */
- /**
- * The Linear Regression Intercept series type.
- *
- * @private
- * @class
- * @name Highcharts.seriesTypes.linearRegressionIntercept
- *
- * @augments Highcharts.Series
- */
- seriesType('linearRegressionIntercept', 'linearRegression',
- /**
- * Linear regression intercept indicator. This series requires `linkedTo`
- * option to be set.
- *
- * @sample {highstock} stock/indicators/linear-regression-intercept
- * Linear intercept slope indicator
- *
- * @extends plotOptions.linearregression
- * @since 7.0.0
- * @product highstock
- * @requires stock/indicators/indicators
- * @requires stock/indicators/regressions
- * @optionparent plotOptions.linearregressionintercept
- */
- {},
- /**
- * @lends Highcharts.Series#
- */
- {
- nameBase: 'Linear Regression Intercept Indicator',
- getEndPointY: function (lineParameters) {
- return lineParameters.intercept;
- }
- });
- /**
- * A linear regression intercept series. If the
- * [type](#series.linearregressionintercept.type) option is not specified, it is
- * inherited from [chart.type](#chart.type).
- *
- * @extends series,plotOptions.linearregressionintercept
- * @since 7.0.0
- * @product highstock
- * @excluding dataParser,dataURL
- * @requires stock/indicators/indicators
- * @requires stock/indicators/regressions
- * @apioption series.linearregressionintercept
- */
- /* ************************************************************************** */
- /**
- * The Linear Regression Angle series type.
- *
- * @private
- * @class
- * @name Highcharts.seriesTypes.linearRegressionAngle
- *
- * @augments Highcharts.Series
- */
- seriesType('linearRegressionAngle', 'linearRegression',
- /**
- * Linear regression angle indicator. This series requires `linkedTo`
- * option to be set.
- *
- * @sample {highstock} stock/indicators/linear-regression-angle
- * Linear intercept angle indicator
- *
- * @extends plotOptions.linearregression
- * @since 7.0.0
- * @product highstock
- * @requires stock/indicators/indicators
- * @requires stock/indicators/regressions
- * @optionparent plotOptions.linearregressionangle
- */
- {
- tooltip: {
- pointFormat: '<span style="color:{point.color}">\u25CF</span>' +
- '{series.name}: <b>{point.y}°</b><br/>'
- }
- },
- /**
- * @lends Highcharts.Series#
- */
- {
- nameBase: 'Linear Regression Angle Indicator',
- /**
- * Convert a slope of a line to angle (in degrees) between
- * the line and x axis
- * @private
- * @param {number} slope of the straight line function
- * @return {number} angle in degrees
- */
- slopeToAngle: function (slope) {
- return Math.atan(slope) * (180 / Math.PI); // rad to deg
- },
- getEndPointY: function (lineParameters) {
- return this.slopeToAngle(lineParameters.slope);
- }
- });
- /**
- * A linear regression intercept series. If the
- * [type](#series.linearregressionangle.type) option is not specified, it is
- * inherited from [chart.type](#chart.type).
- *
- * @extends series,plotOptions.linearregressionangle
- * @since 7.0.0
- * @product highstock
- * @excluding dataParser,dataURL
- * @requires stock/indicators/indicators
- * @requires stock/indicators/regressions
- * @apioption series.linearregressionangle
- */
- ''; // to include the above in the js output
- });
- _registerModule(_modules, 'Stock/Indicators/ABIndicator.js', [_modules['Core/Globals.js'], _modules['Core/Utilities.js'], _modules['Mixins/MultipleLines.js']], function (H, U, multipleLinesMixin) {
- /* *
- *
- * License: www.highcharts.com/license
- *
- * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
- *
- * */
- var correctFloat = U.correctFloat,
- merge = U.merge,
- seriesType = U.seriesType;
- var SMA = H.seriesTypes.sma;
- /* eslint-disable valid-jsdoc */
- /**
- * @private
- */
- function getBaseForBand(low, high, factor) {
- return (((correctFloat(high - low)) /
- ((correctFloat(high + low)) / 2)) * 1000) * factor;
- }
- /**
- * @private
- */
- function getPointUB(high, base) {
- return high * (correctFloat(1 + 2 * base));
- }
- /**
- * @private
- */
- function getPointLB(low, base) {
- return low * (correctFloat(1 - 2 * base));
- }
- /* eslint-enable valid-jsdoc */
- /**
- * The ABands series type
- *
- * @private
- * @class
- * @name Highcharts.seriesTypes.abands
- *
- * @augments Highcharts.Series
- */
- seriesType('abands', 'sma',
- /**
- * Acceleration bands (ABANDS). This series requires the `linkedTo` option
- * to be set and should be loaded after the
- * `stock/indicators/indicators.js`.
- *
- * @sample {highstock} stock/indicators/acceleration-bands
- * Acceleration Bands
- *
- * @extends plotOptions.sma
- * @mixes Highcharts.MultipleLinesMixin
- * @since 7.0.0
- * @product highstock
- * @excluding allAreas, colorAxis, compare, compareBase, joinBy, keys,
- * navigatorOptions, pointInterval, pointIntervalUnit,
- * pointPlacement, pointRange, pointStart, showInNavigator,
- * stacking,
- * @requires stock/indicators/indicators
- * @requires stock/indicators/acceleration-bands
- * @optionparent plotOptions.abands
- */
- {
- params: {
- period: 20,
- /**
- * The algorithms factor value used to calculate bands.
- *
- * @product highstock
- */
- factor: 0.001,
- index: 3
- },
- lineWidth: 1,
- topLine: {
- styles: {
- /**
- * Pixel width of the line.
- */
- lineWidth: 1
- }
- },
- bottomLine: {
- styles: {
- /**
- * Pixel width of the line.
- */
- lineWidth: 1
- }
- },
- dataGrouping: {
- approximation: 'averages'
- }
- },
- /**
- * @lends Highcharts.Series#
- */
- merge(multipleLinesMixin, {
- pointArrayMap: ['top', 'middle', 'bottom'],
- pointValKey: 'middle',
- nameBase: 'Acceleration Bands',
- nameComponents: ['period', 'factor'],
- linesApiNames: ['topLine', 'bottomLine'],
- getValues: function (series, params) {
- var period = params.period,
- factor = params.factor,
- index = params.index,
- xVal = series.xData,
- yVal = series.yData,
- yValLen = yVal ? yVal.length : 0,
- // Upperbands
- UB = [],
- // Lowerbands
- LB = [],
- // ABANDS array structure:
- // 0-date, 1-top line, 2-middle line, 3-bottom line
- ABANDS = [],
- // middle line, top line and bottom line
- ML,
- TL,
- BL,
- date,
- bandBase,
- pointSMA,
- ubSMA,
- lbSMA,
- low = 2,
- high = 1,
- xData = [],
- yData = [],
- slicedX,
- slicedY,
- i;
- if (yValLen < period) {
- return;
- }
- for (i = 0; i <= yValLen; i++) {
- // Get UB and LB values of every point. This condition
- // is necessary, because there is a need to calculate current
- // UB nad LB values simultaneously with given period SMA
- // in one for loop.
- if (i < yValLen) {
- bandBase = getBaseForBand(yVal[i][low], yVal[i][high], factor);
- UB.push(getPointUB(yVal[i][high], bandBase));
- LB.push(getPointLB(yVal[i][low], bandBase));
- }
- if (i >= period) {
- slicedX = xVal.slice(i - period, i);
- slicedY = yVal.slice(i - period, i);
- ubSMA = SMA.prototype.getValues.call(this, {
- xData: slicedX,
- yData: UB.slice(i - period, i)
- }, {
- period: period
- });
- lbSMA = SMA.prototype.getValues.call(this, {
- xData: slicedX,
- yData: LB.slice(i - period, i)
- }, {
- period: period
- });
- pointSMA = SMA.prototype.getValues.call(this, {
- xData: slicedX,
- yData: slicedY
- }, {
- period: period,
- index: index
- });
- date = pointSMA.xData[0];
- TL = ubSMA.yData[0];
- BL = lbSMA.yData[0];
- ML = pointSMA.yData[0];
- ABANDS.push([date, TL, ML, BL]);
- xData.push(date);
- yData.push([TL, ML, BL]);
- }
- }
- return {
- values: ABANDS,
- xData: xData,
- yData: yData
- };
- }
- }));
- /**
- * An Acceleration bands indicator. If the [type](#series.abands.type) option is not
- * specified, it is inherited from [chart.type](#chart.type).
- *
- * @extends series,plotOptions.abands
- * @since 7.0.0
- * @product highstock
- * @excluding allAreas, colorAxis, compare, compareBase, dataParser, dataURL,
- * joinBy, keys, navigatorOptions, pointInterval,
- * pointIntervalUnit, pointPlacement, pointRange, pointStart,
- * stacking, showInNavigator,
- * @requires stock/indicators/indicators
- * @requires stock/indicators/acceleration-bands
- * @apioption series.abands
- */
- ''; // to include the above in jsdoc
- });
- _registerModule(_modules, 'Stock/Indicators/TrendLineIndicator.js', [_modules['Core/Utilities.js']], function (U) {
- /* *
- *
- * License: www.highcharts.com/license
- *
- * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
- *
- * */
- var isArray = U.isArray,
- seriesType = U.seriesType;
- /**
- * The Trend line series type.
- *
- * @private
- * @class
- * @name Highcharts.seriesTypes.trendline
- *
- * @augments Highcharts.Series
- */
- seriesType('trendline', 'sma',
- /**
- * Trendline (linear regression) fits a straight line to the selected data
- * using a method called the Sum Of Least Squares. This series requires the
- * `linkedTo` option to be set.
- *
- * @sample stock/indicators/trendline
- * Trendline indicator
- *
- * @extends plotOptions.sma
- * @since 7.1.3
- * @product highstock
- * @requires stock/indicators/indicators
- * @requires stock/indicators/trendline
- * @optionparent plotOptions.trendline
- */
- {
- /**
- * @excluding period
- */
- params: {
- /**
- * The point index which indicator calculations will base. For
- * example using OHLC data, index=2 means the indicator will be
- * calculated using Low values.
- *
- * @default 3
- */
- index: 3
- }
- },
- /**
- * @lends Highcharts.Series#
- */
- {
- nameBase: 'Trendline',
- nameComponents: false,
- getValues: function (series, params) {
- var xVal = series.xData,
- yVal = series.yData,
- LR = [],
- xData = [],
- yData = [],
- sumX = 0,
- sumY = 0,
- sumXY = 0,
- sumX2 = 0,
- xValLength = xVal.length,
- index = params.index,
- alpha,
- beta,
- i,
- x,
- y;
- // Get sums:
- for (i = 0; i < xValLength; i++) {
- x = xVal[i];
- y = isArray(yVal[i]) ? yVal[i][index] : yVal[i];
- sumX += x;
- sumY += y;
- sumXY += x * y;
- sumX2 += x * x;
- }
- // Get slope and offset:
- alpha = (xValLength * sumXY - sumX * sumY) /
- (xValLength * sumX2 - sumX * sumX);
- if (isNaN(alpha)) {
- alpha = 0;
- }
- beta = (sumY - alpha * sumX) / xValLength;
- // Calculate linear regression:
- for (i = 0; i < xValLength; i++) {
- x = xVal[i];
- y = alpha * x + beta;
- // Prepare arrays required for getValues() method
- LR[i] = [x, y];
- xData[i] = x;
- yData[i] = y;
- }
- return {
- xData: xData,
- yData: yData,
- values: LR
- };
- }
- });
- /**
- * A `TrendLine` series. If the [type](#series.trendline.type) option is not
- * specified, it is inherited from [chart.type](#chart.type).
- *
- * @extends series,plotOptions.trendline
- * @since 7.1.3
- * @product highstock
- * @excluding dataParser, dataURL
- * @requires stock/indicators/indicators
- * @requires stock/indicators/trendline
- * @apioption series.trendline
- */
- ''; // to include the above in the js output
- });
- _registerModule(_modules, 'masters/indicators/indicators-all.src.js', [], function () {
- });
- }));
|