diff --git a/lib/channels/aberr/Aberr.Quantower.Tests.cs b/lib/channels/aberr/tests/Aberr.Quantower.Tests.cs similarity index 100% rename from lib/channels/aberr/Aberr.Quantower.Tests.cs rename to lib/channels/aberr/tests/Aberr.Quantower.Tests.cs diff --git a/lib/channels/aberr/Aberr.Tests.cs b/lib/channels/aberr/tests/Aberr.Tests.cs similarity index 100% rename from lib/channels/aberr/Aberr.Tests.cs rename to lib/channels/aberr/tests/Aberr.Tests.cs diff --git a/lib/channels/aberr/Aberr.Validation.Tests.cs b/lib/channels/aberr/tests/Aberr.Validation.Tests.cs similarity index 100% rename from lib/channels/aberr/Aberr.Validation.Tests.cs rename to lib/channels/aberr/tests/Aberr.Validation.Tests.cs diff --git a/lib/channels/accbands/AccBands.Quantower.Tests.cs b/lib/channels/accbands/tests/AccBands.Quantower.Tests.cs similarity index 100% rename from lib/channels/accbands/AccBands.Quantower.Tests.cs rename to lib/channels/accbands/tests/AccBands.Quantower.Tests.cs diff --git a/lib/channels/accbands/AccBands.Tests.cs b/lib/channels/accbands/tests/AccBands.Tests.cs similarity index 100% rename from lib/channels/accbands/AccBands.Tests.cs rename to lib/channels/accbands/tests/AccBands.Tests.cs diff --git a/lib/channels/accbands/AccBands.Validation.Tests.cs b/lib/channels/accbands/tests/AccBands.Validation.Tests.cs similarity index 100% rename from lib/channels/accbands/AccBands.Validation.Tests.cs rename to lib/channels/accbands/tests/AccBands.Validation.Tests.cs diff --git a/lib/channels/apchannel/Apchannel.Quantower.Tests.cs b/lib/channels/apchannel/tests/Apchannel.Quantower.Tests.cs similarity index 100% rename from lib/channels/apchannel/Apchannel.Quantower.Tests.cs rename to lib/channels/apchannel/tests/Apchannel.Quantower.Tests.cs diff --git a/lib/channels/apchannel/apchannel.Tests.cs b/lib/channels/apchannel/tests/apchannel.Tests.cs similarity index 100% rename from lib/channels/apchannel/apchannel.Tests.cs rename to lib/channels/apchannel/tests/apchannel.Tests.cs diff --git a/lib/channels/apchannel/apchannel.Validation.Tests.cs b/lib/channels/apchannel/tests/apchannel.Validation.Tests.cs similarity index 100% rename from lib/channels/apchannel/apchannel.Validation.Tests.cs rename to lib/channels/apchannel/tests/apchannel.Validation.Tests.cs diff --git a/lib/channels/apz/Apz.Quantower.Tests.cs b/lib/channels/apz/tests/Apz.Quantower.Tests.cs similarity index 100% rename from lib/channels/apz/Apz.Quantower.Tests.cs rename to lib/channels/apz/tests/Apz.Quantower.Tests.cs diff --git a/lib/channels/apz/Apz.Tests.cs b/lib/channels/apz/tests/Apz.Tests.cs similarity index 100% rename from lib/channels/apz/Apz.Tests.cs rename to lib/channels/apz/tests/Apz.Tests.cs diff --git a/lib/channels/apz/Apz.Validation.Tests.cs b/lib/channels/apz/tests/Apz.Validation.Tests.cs similarity index 100% rename from lib/channels/apz/Apz.Validation.Tests.cs rename to lib/channels/apz/tests/Apz.Validation.Tests.cs diff --git a/lib/channels/atrbands/AtrBands.Quantower.Tests.cs b/lib/channels/atrbands/tests/AtrBands.Quantower.Tests.cs similarity index 100% rename from lib/channels/atrbands/AtrBands.Quantower.Tests.cs rename to lib/channels/atrbands/tests/AtrBands.Quantower.Tests.cs diff --git a/lib/channels/atrbands/AtrBands.Tests.cs b/lib/channels/atrbands/tests/AtrBands.Tests.cs similarity index 100% rename from lib/channels/atrbands/AtrBands.Tests.cs rename to lib/channels/atrbands/tests/AtrBands.Tests.cs diff --git a/lib/channels/atrbands/AtrBands.Validation.Tests.cs b/lib/channels/atrbands/tests/AtrBands.Validation.Tests.cs similarity index 100% rename from lib/channels/atrbands/AtrBands.Validation.Tests.cs rename to lib/channels/atrbands/tests/AtrBands.Validation.Tests.cs diff --git a/lib/channels/bbands/Bbands.Quantower.Tests.cs b/lib/channels/bbands/tests/Bbands.Quantower.Tests.cs similarity index 100% rename from lib/channels/bbands/Bbands.Quantower.Tests.cs rename to lib/channels/bbands/tests/Bbands.Quantower.Tests.cs diff --git a/lib/channels/bbands/Bbands.Tests.cs b/lib/channels/bbands/tests/Bbands.Tests.cs similarity index 100% rename from lib/channels/bbands/Bbands.Tests.cs rename to lib/channels/bbands/tests/Bbands.Tests.cs diff --git a/lib/channels/bbands/Bbands.Validation.Tests.cs b/lib/channels/bbands/tests/Bbands.Validation.Tests.cs similarity index 100% rename from lib/channels/bbands/Bbands.Validation.Tests.cs rename to lib/channels/bbands/tests/Bbands.Validation.Tests.cs diff --git a/lib/channels/dchannel/Dchannel.Quantower.Tests.cs b/lib/channels/dchannel/tests/Dchannel.Quantower.Tests.cs similarity index 100% rename from lib/channels/dchannel/Dchannel.Quantower.Tests.cs rename to lib/channels/dchannel/tests/Dchannel.Quantower.Tests.cs diff --git a/lib/channels/dchannel/Dchannel.Tests.cs b/lib/channels/dchannel/tests/Dchannel.Tests.cs similarity index 100% rename from lib/channels/dchannel/Dchannel.Tests.cs rename to lib/channels/dchannel/tests/Dchannel.Tests.cs diff --git a/lib/channels/dchannel/Dchannel.Validation.Tests.cs b/lib/channels/dchannel/tests/Dchannel.Validation.Tests.cs similarity index 100% rename from lib/channels/dchannel/Dchannel.Validation.Tests.cs rename to lib/channels/dchannel/tests/Dchannel.Validation.Tests.cs diff --git a/lib/channels/decaychannel/Decaychannel.Quantower.Tests.cs b/lib/channels/decaychannel/tests/Decaychannel.Quantower.Tests.cs similarity index 100% rename from lib/channels/decaychannel/Decaychannel.Quantower.Tests.cs rename to lib/channels/decaychannel/tests/Decaychannel.Quantower.Tests.cs diff --git a/lib/channels/decaychannel/Decaychannel.Tests.cs b/lib/channels/decaychannel/tests/Decaychannel.Tests.cs similarity index 100% rename from lib/channels/decaychannel/Decaychannel.Tests.cs rename to lib/channels/decaychannel/tests/Decaychannel.Tests.cs diff --git a/lib/channels/decaychannel/Decaychannel.Validation.Tests.cs b/lib/channels/decaychannel/tests/Decaychannel.Validation.Tests.cs similarity index 100% rename from lib/channels/decaychannel/Decaychannel.Validation.Tests.cs rename to lib/channels/decaychannel/tests/Decaychannel.Validation.Tests.cs diff --git a/lib/channels/fcb/Fcb.Quantower.Tests.cs b/lib/channels/fcb/tests/Fcb.Quantower.Tests.cs similarity index 100% rename from lib/channels/fcb/Fcb.Quantower.Tests.cs rename to lib/channels/fcb/tests/Fcb.Quantower.Tests.cs diff --git a/lib/channels/fcb/Fcb.Tests.cs b/lib/channels/fcb/tests/Fcb.Tests.cs similarity index 100% rename from lib/channels/fcb/Fcb.Tests.cs rename to lib/channels/fcb/tests/Fcb.Tests.cs diff --git a/lib/channels/fcb/Fcb.Validation.Tests.cs b/lib/channels/fcb/tests/Fcb.Validation.Tests.cs similarity index 100% rename from lib/channels/fcb/Fcb.Validation.Tests.cs rename to lib/channels/fcb/tests/Fcb.Validation.Tests.cs diff --git a/lib/channels/jbands/Jbands.Quantower.Tests.cs b/lib/channels/jbands/tests/Jbands.Quantower.Tests.cs similarity index 100% rename from lib/channels/jbands/Jbands.Quantower.Tests.cs rename to lib/channels/jbands/tests/Jbands.Quantower.Tests.cs diff --git a/lib/channels/jbands/Jbands.Tests.cs b/lib/channels/jbands/tests/Jbands.Tests.cs similarity index 100% rename from lib/channels/jbands/Jbands.Tests.cs rename to lib/channels/jbands/tests/Jbands.Tests.cs diff --git a/lib/channels/jbands/Jbands.Validation.Tests.cs b/lib/channels/jbands/tests/Jbands.Validation.Tests.cs similarity index 100% rename from lib/channels/jbands/Jbands.Validation.Tests.cs rename to lib/channels/jbands/tests/Jbands.Validation.Tests.cs diff --git a/lib/channels/kchannel/Kchannel.Quantower.Tests.cs b/lib/channels/kchannel/tests/Kchannel.Quantower.Tests.cs similarity index 100% rename from lib/channels/kchannel/Kchannel.Quantower.Tests.cs rename to lib/channels/kchannel/tests/Kchannel.Quantower.Tests.cs diff --git a/lib/channels/kchannel/Kchannel.Tests.cs b/lib/channels/kchannel/tests/Kchannel.Tests.cs similarity index 100% rename from lib/channels/kchannel/Kchannel.Tests.cs rename to lib/channels/kchannel/tests/Kchannel.Tests.cs diff --git a/lib/channels/kchannel/Kchannel.Validation.Tests.cs b/lib/channels/kchannel/tests/Kchannel.Validation.Tests.cs similarity index 100% rename from lib/channels/kchannel/Kchannel.Validation.Tests.cs rename to lib/channels/kchannel/tests/Kchannel.Validation.Tests.cs diff --git a/lib/channels/maenv/Maenv.Quantower.Tests.cs b/lib/channels/maenv/tests/Maenv.Quantower.Tests.cs similarity index 100% rename from lib/channels/maenv/Maenv.Quantower.Tests.cs rename to lib/channels/maenv/tests/Maenv.Quantower.Tests.cs diff --git a/lib/channels/maenv/Maenv.Tests.cs b/lib/channels/maenv/tests/Maenv.Tests.cs similarity index 100% rename from lib/channels/maenv/Maenv.Tests.cs rename to lib/channels/maenv/tests/Maenv.Tests.cs diff --git a/lib/channels/maenv/Maenv.Validation.Tests.cs b/lib/channels/maenv/tests/Maenv.Validation.Tests.cs similarity index 100% rename from lib/channels/maenv/Maenv.Validation.Tests.cs rename to lib/channels/maenv/tests/Maenv.Validation.Tests.cs diff --git a/lib/channels/mmchannel/Mmchannel.Quantower.Tests.cs b/lib/channels/mmchannel/tests/Mmchannel.Quantower.Tests.cs similarity index 100% rename from lib/channels/mmchannel/Mmchannel.Quantower.Tests.cs rename to lib/channels/mmchannel/tests/Mmchannel.Quantower.Tests.cs diff --git a/lib/channels/mmchannel/Mmchannel.Tests.cs b/lib/channels/mmchannel/tests/Mmchannel.Tests.cs similarity index 100% rename from lib/channels/mmchannel/Mmchannel.Tests.cs rename to lib/channels/mmchannel/tests/Mmchannel.Tests.cs diff --git a/lib/channels/mmchannel/Mmchannel.Validation.Tests.cs b/lib/channels/mmchannel/tests/Mmchannel.Validation.Tests.cs similarity index 100% rename from lib/channels/mmchannel/Mmchannel.Validation.Tests.cs rename to lib/channels/mmchannel/tests/Mmchannel.Validation.Tests.cs diff --git a/lib/channels/pchannel/Pchannel.Quantower.Tests.cs b/lib/channels/pchannel/tests/Pchannel.Quantower.Tests.cs similarity index 100% rename from lib/channels/pchannel/Pchannel.Quantower.Tests.cs rename to lib/channels/pchannel/tests/Pchannel.Quantower.Tests.cs diff --git a/lib/channels/pchannel/Pchannel.Tests.cs b/lib/channels/pchannel/tests/Pchannel.Tests.cs similarity index 100% rename from lib/channels/pchannel/Pchannel.Tests.cs rename to lib/channels/pchannel/tests/Pchannel.Tests.cs diff --git a/lib/channels/pchannel/Pchannel.Validation.Tests.cs b/lib/channels/pchannel/tests/Pchannel.Validation.Tests.cs similarity index 100% rename from lib/channels/pchannel/Pchannel.Validation.Tests.cs rename to lib/channels/pchannel/tests/Pchannel.Validation.Tests.cs diff --git a/lib/channels/regchannel/Regchannel.Quantower.Tests.cs b/lib/channels/regchannel/tests/Regchannel.Quantower.Tests.cs similarity index 100% rename from lib/channels/regchannel/Regchannel.Quantower.Tests.cs rename to lib/channels/regchannel/tests/Regchannel.Quantower.Tests.cs diff --git a/lib/channels/regchannel/Regchannel.Tests.cs b/lib/channels/regchannel/tests/Regchannel.Tests.cs similarity index 100% rename from lib/channels/regchannel/Regchannel.Tests.cs rename to lib/channels/regchannel/tests/Regchannel.Tests.cs diff --git a/lib/channels/regchannel/Regchannel.Validation.Tests.cs b/lib/channels/regchannel/tests/Regchannel.Validation.Tests.cs similarity index 100% rename from lib/channels/regchannel/Regchannel.Validation.Tests.cs rename to lib/channels/regchannel/tests/Regchannel.Validation.Tests.cs diff --git a/lib/channels/sdchannel/Sdchannel.Quantower.Tests.cs b/lib/channels/sdchannel/tests/Sdchannel.Quantower.Tests.cs similarity index 100% rename from lib/channels/sdchannel/Sdchannel.Quantower.Tests.cs rename to lib/channels/sdchannel/tests/Sdchannel.Quantower.Tests.cs diff --git a/lib/channels/sdchannel/Sdchannel.Tests.cs b/lib/channels/sdchannel/tests/Sdchannel.Tests.cs similarity index 100% rename from lib/channels/sdchannel/Sdchannel.Tests.cs rename to lib/channels/sdchannel/tests/Sdchannel.Tests.cs diff --git a/lib/channels/sdchannel/Sdchannel.Validation.Tests.cs b/lib/channels/sdchannel/tests/Sdchannel.Validation.Tests.cs similarity index 100% rename from lib/channels/sdchannel/Sdchannel.Validation.Tests.cs rename to lib/channels/sdchannel/tests/Sdchannel.Validation.Tests.cs diff --git a/lib/channels/starchannel/Starchannel.Quantower.Tests.cs b/lib/channels/starchannel/tests/Starchannel.Quantower.Tests.cs similarity index 100% rename from lib/channels/starchannel/Starchannel.Quantower.Tests.cs rename to lib/channels/starchannel/tests/Starchannel.Quantower.Tests.cs diff --git a/lib/channels/starchannel/Starchannel.Tests.cs b/lib/channels/starchannel/tests/Starchannel.Tests.cs similarity index 100% rename from lib/channels/starchannel/Starchannel.Tests.cs rename to lib/channels/starchannel/tests/Starchannel.Tests.cs diff --git a/lib/channels/starchannel/Starchannel.Validation.Tests.cs b/lib/channels/starchannel/tests/Starchannel.Validation.Tests.cs similarity index 100% rename from lib/channels/starchannel/Starchannel.Validation.Tests.cs rename to lib/channels/starchannel/tests/Starchannel.Validation.Tests.cs diff --git a/lib/channels/stbands/Stbands.Quantower.Tests.cs b/lib/channels/stbands/tests/Stbands.Quantower.Tests.cs similarity index 100% rename from lib/channels/stbands/Stbands.Quantower.Tests.cs rename to lib/channels/stbands/tests/Stbands.Quantower.Tests.cs diff --git a/lib/channels/stbands/Stbands.Tests.cs b/lib/channels/stbands/tests/Stbands.Tests.cs similarity index 100% rename from lib/channels/stbands/Stbands.Tests.cs rename to lib/channels/stbands/tests/Stbands.Tests.cs diff --git a/lib/channels/stbands/Stbands.Validation.Tests.cs b/lib/channels/stbands/tests/Stbands.Validation.Tests.cs similarity index 100% rename from lib/channels/stbands/Stbands.Validation.Tests.cs rename to lib/channels/stbands/tests/Stbands.Validation.Tests.cs diff --git a/lib/channels/ttm_lrc/TtmLrc.Quantower.Tests.cs b/lib/channels/ttm_lrc/tests/TtmLrc.Quantower.Tests.cs similarity index 100% rename from lib/channels/ttm_lrc/TtmLrc.Quantower.Tests.cs rename to lib/channels/ttm_lrc/tests/TtmLrc.Quantower.Tests.cs diff --git a/lib/channels/ttm_lrc/TtmLrc.Tests.cs b/lib/channels/ttm_lrc/tests/TtmLrc.Tests.cs similarity index 100% rename from lib/channels/ttm_lrc/TtmLrc.Tests.cs rename to lib/channels/ttm_lrc/tests/TtmLrc.Tests.cs diff --git a/lib/channels/ttm_lrc/TtmLrc.Validation.Tests.cs b/lib/channels/ttm_lrc/tests/TtmLrc.Validation.Tests.cs similarity index 100% rename from lib/channels/ttm_lrc/TtmLrc.Validation.Tests.cs rename to lib/channels/ttm_lrc/tests/TtmLrc.Validation.Tests.cs diff --git a/lib/channels/ubands/Ubands.Quantower.Tests.cs b/lib/channels/ubands/tests/Ubands.Quantower.Tests.cs similarity index 100% rename from lib/channels/ubands/Ubands.Quantower.Tests.cs rename to lib/channels/ubands/tests/Ubands.Quantower.Tests.cs diff --git a/lib/channels/ubands/Ubands.Tests.cs b/lib/channels/ubands/tests/Ubands.Tests.cs similarity index 100% rename from lib/channels/ubands/Ubands.Tests.cs rename to lib/channels/ubands/tests/Ubands.Tests.cs diff --git a/lib/channels/ubands/Ubands.Validation.Tests.cs b/lib/channels/ubands/tests/Ubands.Validation.Tests.cs similarity index 100% rename from lib/channels/ubands/Ubands.Validation.Tests.cs rename to lib/channels/ubands/tests/Ubands.Validation.Tests.cs diff --git a/lib/channels/uchannel/Uchannel.Quantower.Tests.cs b/lib/channels/uchannel/tests/Uchannel.Quantower.Tests.cs similarity index 100% rename from lib/channels/uchannel/Uchannel.Quantower.Tests.cs rename to lib/channels/uchannel/tests/Uchannel.Quantower.Tests.cs diff --git a/lib/channels/uchannel/Uchannel.Tests.cs b/lib/channels/uchannel/tests/Uchannel.Tests.cs similarity index 100% rename from lib/channels/uchannel/Uchannel.Tests.cs rename to lib/channels/uchannel/tests/Uchannel.Tests.cs diff --git a/lib/channels/uchannel/Uchannel.Validation.Tests.cs b/lib/channels/uchannel/tests/Uchannel.Validation.Tests.cs similarity index 100% rename from lib/channels/uchannel/Uchannel.Validation.Tests.cs rename to lib/channels/uchannel/tests/Uchannel.Validation.Tests.cs diff --git a/lib/channels/vwapbands/Vwapbands.Quantower.Tests.cs b/lib/channels/vwapbands/tests/Vwapbands.Quantower.Tests.cs similarity index 100% rename from lib/channels/vwapbands/Vwapbands.Quantower.Tests.cs rename to lib/channels/vwapbands/tests/Vwapbands.Quantower.Tests.cs diff --git a/lib/channels/vwapbands/Vwapbands.Tests.cs b/lib/channels/vwapbands/tests/Vwapbands.Tests.cs similarity index 100% rename from lib/channels/vwapbands/Vwapbands.Tests.cs rename to lib/channels/vwapbands/tests/Vwapbands.Tests.cs diff --git a/lib/channels/vwapbands/Vwapbands.Validation.Tests.cs b/lib/channels/vwapbands/tests/Vwapbands.Validation.Tests.cs similarity index 100% rename from lib/channels/vwapbands/Vwapbands.Validation.Tests.cs rename to lib/channels/vwapbands/tests/Vwapbands.Validation.Tests.cs diff --git a/lib/channels/vwapsd/Vwapsd.Quantower.Tests.cs b/lib/channels/vwapsd/tests/Vwapsd.Quantower.Tests.cs similarity index 100% rename from lib/channels/vwapsd/Vwapsd.Quantower.Tests.cs rename to lib/channels/vwapsd/tests/Vwapsd.Quantower.Tests.cs diff --git a/lib/channels/vwapsd/Vwapsd.Tests.cs b/lib/channels/vwapsd/tests/Vwapsd.Tests.cs similarity index 100% rename from lib/channels/vwapsd/Vwapsd.Tests.cs rename to lib/channels/vwapsd/tests/Vwapsd.Tests.cs diff --git a/lib/channels/vwapsd/Vwapsd.Validation.Tests.cs b/lib/channels/vwapsd/tests/Vwapsd.Validation.Tests.cs similarity index 100% rename from lib/channels/vwapsd/Vwapsd.Validation.Tests.cs rename to lib/channels/vwapsd/tests/Vwapsd.Validation.Tests.cs diff --git a/lib/core/avgprice/Avgprice.Quantower.Tests.cs b/lib/core/avgprice/tests/Avgprice.Quantower.Tests.cs similarity index 100% rename from lib/core/avgprice/Avgprice.Quantower.Tests.cs rename to lib/core/avgprice/tests/Avgprice.Quantower.Tests.cs diff --git a/lib/core/avgprice/Avgprice.Tests.cs b/lib/core/avgprice/tests/Avgprice.Tests.cs similarity index 100% rename from lib/core/avgprice/Avgprice.Tests.cs rename to lib/core/avgprice/tests/Avgprice.Tests.cs diff --git a/lib/core/avgprice/Avgprice.Validation.Tests.cs b/lib/core/avgprice/tests/Avgprice.Validation.Tests.cs similarity index 100% rename from lib/core/avgprice/Avgprice.Validation.Tests.cs rename to lib/core/avgprice/tests/Avgprice.Validation.Tests.cs diff --git a/lib/core/collections/MonotonicDeque.Tests.cs b/lib/core/collections/tests/MonotonicDeque.Tests.cs similarity index 100% rename from lib/core/collections/MonotonicDeque.Tests.cs rename to lib/core/collections/tests/MonotonicDeque.Tests.cs diff --git a/lib/core/ha/Ha.Quantower.Tests.cs b/lib/core/ha/tests/Ha.Quantower.Tests.cs similarity index 100% rename from lib/core/ha/Ha.Quantower.Tests.cs rename to lib/core/ha/tests/Ha.Quantower.Tests.cs diff --git a/lib/core/ha/Ha.Tests.cs b/lib/core/ha/tests/Ha.Tests.cs similarity index 100% rename from lib/core/ha/Ha.Tests.cs rename to lib/core/ha/tests/Ha.Tests.cs diff --git a/lib/core/ha/Ha.Validation.Tests.cs b/lib/core/ha/tests/Ha.Validation.Tests.cs similarity index 100% rename from lib/core/ha/Ha.Validation.Tests.cs rename to lib/core/ha/tests/Ha.Validation.Tests.cs diff --git a/lib/core/medprice/Medprice.Quantower.Tests.cs b/lib/core/medprice/tests/Medprice.Quantower.Tests.cs similarity index 100% rename from lib/core/medprice/Medprice.Quantower.Tests.cs rename to lib/core/medprice/tests/Medprice.Quantower.Tests.cs diff --git a/lib/core/medprice/Medprice.Tests.cs b/lib/core/medprice/tests/Medprice.Tests.cs similarity index 100% rename from lib/core/medprice/Medprice.Tests.cs rename to lib/core/medprice/tests/Medprice.Tests.cs diff --git a/lib/core/medprice/Medprice.Validation.Tests.cs b/lib/core/medprice/tests/Medprice.Validation.Tests.cs similarity index 100% rename from lib/core/medprice/Medprice.Validation.Tests.cs rename to lib/core/medprice/tests/Medprice.Validation.Tests.cs diff --git a/lib/core/midbody/Midbody.Quantower.Tests.cs b/lib/core/midbody/tests/Midbody.Quantower.Tests.cs similarity index 100% rename from lib/core/midbody/Midbody.Quantower.Tests.cs rename to lib/core/midbody/tests/Midbody.Quantower.Tests.cs diff --git a/lib/core/midbody/Midbody.Tests.cs b/lib/core/midbody/tests/Midbody.Tests.cs similarity index 100% rename from lib/core/midbody/Midbody.Tests.cs rename to lib/core/midbody/tests/Midbody.Tests.cs diff --git a/lib/core/midbody/Midbody.Validation.Tests.cs b/lib/core/midbody/tests/Midbody.Validation.Tests.cs similarity index 100% rename from lib/core/midbody/Midbody.Validation.Tests.cs rename to lib/core/midbody/tests/Midbody.Validation.Tests.cs diff --git a/lib/core/midpoint/Midpoint.Quantower.Tests.cs b/lib/core/midpoint/tests/Midpoint.Quantower.Tests.cs similarity index 100% rename from lib/core/midpoint/Midpoint.Quantower.Tests.cs rename to lib/core/midpoint/tests/Midpoint.Quantower.Tests.cs diff --git a/lib/core/midpoint/Midpoint.Tests.cs b/lib/core/midpoint/tests/Midpoint.Tests.cs similarity index 100% rename from lib/core/midpoint/Midpoint.Tests.cs rename to lib/core/midpoint/tests/Midpoint.Tests.cs diff --git a/lib/core/midpoint/Midpoint.Validation.Tests.cs b/lib/core/midpoint/tests/Midpoint.Validation.Tests.cs similarity index 100% rename from lib/core/midpoint/Midpoint.Validation.Tests.cs rename to lib/core/midpoint/tests/Midpoint.Validation.Tests.cs diff --git a/lib/core/midprice/Midprice.Quantower.Tests.cs b/lib/core/midprice/tests/Midprice.Quantower.Tests.cs similarity index 100% rename from lib/core/midprice/Midprice.Quantower.Tests.cs rename to lib/core/midprice/tests/Midprice.Quantower.Tests.cs diff --git a/lib/core/midprice/Midprice.Tests.cs b/lib/core/midprice/tests/Midprice.Tests.cs similarity index 100% rename from lib/core/midprice/Midprice.Tests.cs rename to lib/core/midprice/tests/Midprice.Tests.cs diff --git a/lib/core/midprice/Midprice.Validation.Tests.cs b/lib/core/midprice/tests/Midprice.Validation.Tests.cs similarity index 100% rename from lib/core/midprice/Midprice.Validation.Tests.cs rename to lib/core/midprice/tests/Midprice.Validation.Tests.cs diff --git a/lib/core/ringbuffer/RingBuffer.Tests.cs b/lib/core/ringbuffer/tests/RingBuffer.Tests.cs similarity index 100% rename from lib/core/ringbuffer/RingBuffer.Tests.cs rename to lib/core/ringbuffer/tests/RingBuffer.Tests.cs diff --git a/lib/core/simd/ErrorHelpers.Tests.cs b/lib/core/simd/tests/ErrorHelpers.Tests.cs similarity index 100% rename from lib/core/simd/ErrorHelpers.Tests.cs rename to lib/core/simd/tests/ErrorHelpers.Tests.cs diff --git a/lib/core/simd/SimdExtensions.Tests.cs b/lib/core/simd/tests/SimdExtensions.Tests.cs similarity index 100% rename from lib/core/simd/SimdExtensions.Tests.cs rename to lib/core/simd/tests/SimdExtensions.Tests.cs diff --git a/lib/core/tbar/TBar.Tests.cs b/lib/core/tbar/tests/TBar.Tests.cs similarity index 100% rename from lib/core/tbar/TBar.Tests.cs rename to lib/core/tbar/tests/TBar.Tests.cs diff --git a/lib/core/tbarseries/TBarSeries.Tests.cs b/lib/core/tbarseries/tests/TBarSeries.Tests.cs similarity index 100% rename from lib/core/tbarseries/TBarSeries.Tests.cs rename to lib/core/tbarseries/tests/TBarSeries.Tests.cs diff --git a/lib/core/BiInputIndicatorBase.Tests.cs b/lib/core/tests/BiInputIndicatorBase.Tests.cs similarity index 100% rename from lib/core/BiInputIndicatorBase.Tests.cs rename to lib/core/tests/BiInputIndicatorBase.Tests.cs diff --git a/lib/core/tseries/ITValuePublisher.Tests.cs b/lib/core/tseries/tests/ITValuePublisher.Tests.cs similarity index 100% rename from lib/core/tseries/ITValuePublisher.Tests.cs rename to lib/core/tseries/tests/ITValuePublisher.Tests.cs diff --git a/lib/core/tseries/TSeries.Tests.cs b/lib/core/tseries/tests/TSeries.Tests.cs similarity index 100% rename from lib/core/tseries/TSeries.Tests.cs rename to lib/core/tseries/tests/TSeries.Tests.cs diff --git a/lib/core/tvalue/TValue.Tests.cs b/lib/core/tvalue/tests/TValue.Tests.cs similarity index 100% rename from lib/core/tvalue/TValue.Tests.cs rename to lib/core/tvalue/tests/TValue.Tests.cs diff --git a/lib/core/typprice/Typprice.Quantower.Tests.cs b/lib/core/typprice/tests/Typprice.Quantower.Tests.cs similarity index 100% rename from lib/core/typprice/Typprice.Quantower.Tests.cs rename to lib/core/typprice/tests/Typprice.Quantower.Tests.cs diff --git a/lib/core/typprice/Typprice.Tests.cs b/lib/core/typprice/tests/Typprice.Tests.cs similarity index 100% rename from lib/core/typprice/Typprice.Tests.cs rename to lib/core/typprice/tests/Typprice.Tests.cs diff --git a/lib/core/typprice/Typprice.Validation.Tests.cs b/lib/core/typprice/tests/Typprice.Validation.Tests.cs similarity index 100% rename from lib/core/typprice/Typprice.Validation.Tests.cs rename to lib/core/typprice/tests/Typprice.Validation.Tests.cs diff --git a/lib/core/wclprice/Wclprice.Quantower.Tests.cs b/lib/core/wclprice/tests/Wclprice.Quantower.Tests.cs similarity index 100% rename from lib/core/wclprice/Wclprice.Quantower.Tests.cs rename to lib/core/wclprice/tests/Wclprice.Quantower.Tests.cs diff --git a/lib/core/wclprice/Wclprice.Tests.cs b/lib/core/wclprice/tests/Wclprice.Tests.cs similarity index 100% rename from lib/core/wclprice/Wclprice.Tests.cs rename to lib/core/wclprice/tests/Wclprice.Tests.cs diff --git a/lib/core/wclprice/Wclprice.Validation.Tests.cs b/lib/core/wclprice/tests/Wclprice.Validation.Tests.cs similarity index 100% rename from lib/core/wclprice/Wclprice.Validation.Tests.cs rename to lib/core/wclprice/tests/Wclprice.Validation.Tests.cs diff --git a/lib/cycles/ccor/Ccor.Quantower.Tests.cs b/lib/cycles/ccor/tests/Ccor.Quantower.Tests.cs similarity index 100% rename from lib/cycles/ccor/Ccor.Quantower.Tests.cs rename to lib/cycles/ccor/tests/Ccor.Quantower.Tests.cs diff --git a/lib/cycles/ccor/Ccor.Tests.cs b/lib/cycles/ccor/tests/Ccor.Tests.cs similarity index 100% rename from lib/cycles/ccor/Ccor.Tests.cs rename to lib/cycles/ccor/tests/Ccor.Tests.cs diff --git a/lib/cycles/ccor/Ccor.Validation.Tests.cs b/lib/cycles/ccor/tests/Ccor.Validation.Tests.cs similarity index 100% rename from lib/cycles/ccor/Ccor.Validation.Tests.cs rename to lib/cycles/ccor/tests/Ccor.Validation.Tests.cs diff --git a/lib/cycles/ccyc/Ccyc.Quantower.Tests.cs b/lib/cycles/ccyc/tests/Ccyc.Quantower.Tests.cs similarity index 100% rename from lib/cycles/ccyc/Ccyc.Quantower.Tests.cs rename to lib/cycles/ccyc/tests/Ccyc.Quantower.Tests.cs diff --git a/lib/cycles/ccyc/Ccyc.Tests.cs b/lib/cycles/ccyc/tests/Ccyc.Tests.cs similarity index 100% rename from lib/cycles/ccyc/Ccyc.Tests.cs rename to lib/cycles/ccyc/tests/Ccyc.Tests.cs diff --git a/lib/cycles/ccyc/Ccyc.Validation.Tests.cs b/lib/cycles/ccyc/tests/Ccyc.Validation.Tests.cs similarity index 100% rename from lib/cycles/ccyc/Ccyc.Validation.Tests.cs rename to lib/cycles/ccyc/tests/Ccyc.Validation.Tests.cs diff --git a/lib/cycles/cg/Cg.Quantower.Tests.cs b/lib/cycles/cg/tests/Cg.Quantower.Tests.cs similarity index 100% rename from lib/cycles/cg/Cg.Quantower.Tests.cs rename to lib/cycles/cg/tests/Cg.Quantower.Tests.cs diff --git a/lib/cycles/cg/Cg.Tests.cs b/lib/cycles/cg/tests/Cg.Tests.cs similarity index 100% rename from lib/cycles/cg/Cg.Tests.cs rename to lib/cycles/cg/tests/Cg.Tests.cs diff --git a/lib/cycles/cg/Cg.Validation.Tests.cs b/lib/cycles/cg/tests/Cg.Validation.Tests.cs similarity index 100% rename from lib/cycles/cg/Cg.Validation.Tests.cs rename to lib/cycles/cg/tests/Cg.Validation.Tests.cs diff --git a/lib/cycles/dsp/Dsp.Quantower.Tests.cs b/lib/cycles/dsp/tests/Dsp.Quantower.Tests.cs similarity index 100% rename from lib/cycles/dsp/Dsp.Quantower.Tests.cs rename to lib/cycles/dsp/tests/Dsp.Quantower.Tests.cs diff --git a/lib/cycles/dsp/Dsp.Tests.cs b/lib/cycles/dsp/tests/Dsp.Tests.cs similarity index 100% rename from lib/cycles/dsp/Dsp.Tests.cs rename to lib/cycles/dsp/tests/Dsp.Tests.cs diff --git a/lib/cycles/dsp/Dsp.Validation.Tests.cs b/lib/cycles/dsp/tests/Dsp.Validation.Tests.cs similarity index 100% rename from lib/cycles/dsp/Dsp.Validation.Tests.cs rename to lib/cycles/dsp/tests/Dsp.Validation.Tests.cs diff --git a/lib/cycles/eacp/Eacp.Quantower.Tests.cs b/lib/cycles/eacp/tests/Eacp.Quantower.Tests.cs similarity index 100% rename from lib/cycles/eacp/Eacp.Quantower.Tests.cs rename to lib/cycles/eacp/tests/Eacp.Quantower.Tests.cs diff --git a/lib/cycles/eacp/Eacp.Tests.cs b/lib/cycles/eacp/tests/Eacp.Tests.cs similarity index 100% rename from lib/cycles/eacp/Eacp.Tests.cs rename to lib/cycles/eacp/tests/Eacp.Tests.cs diff --git a/lib/cycles/eacp/Eacp.Validation.Tests.cs b/lib/cycles/eacp/tests/Eacp.Validation.Tests.cs similarity index 100% rename from lib/cycles/eacp/Eacp.Validation.Tests.cs rename to lib/cycles/eacp/tests/Eacp.Validation.Tests.cs diff --git a/lib/cycles/ebsw/Ebsw.Quantower.Tests.cs b/lib/cycles/ebsw/tests/Ebsw.Quantower.Tests.cs similarity index 100% rename from lib/cycles/ebsw/Ebsw.Quantower.Tests.cs rename to lib/cycles/ebsw/tests/Ebsw.Quantower.Tests.cs diff --git a/lib/cycles/ebsw/Ebsw.Tests.cs b/lib/cycles/ebsw/tests/Ebsw.Tests.cs similarity index 100% rename from lib/cycles/ebsw/Ebsw.Tests.cs rename to lib/cycles/ebsw/tests/Ebsw.Tests.cs diff --git a/lib/cycles/ebsw/Ebsw.Validation.Tests.cs b/lib/cycles/ebsw/tests/Ebsw.Validation.Tests.cs similarity index 100% rename from lib/cycles/ebsw/Ebsw.Validation.Tests.cs rename to lib/cycles/ebsw/tests/Ebsw.Validation.Tests.cs diff --git a/lib/cycles/homod/Homod.Quantower.Tests.cs b/lib/cycles/homod/tests/Homod.Quantower.Tests.cs similarity index 100% rename from lib/cycles/homod/Homod.Quantower.Tests.cs rename to lib/cycles/homod/tests/Homod.Quantower.Tests.cs diff --git a/lib/cycles/homod/Homod.Tests.cs b/lib/cycles/homod/tests/Homod.Tests.cs similarity index 100% rename from lib/cycles/homod/Homod.Tests.cs rename to lib/cycles/homod/tests/Homod.Tests.cs diff --git a/lib/cycles/homod/Homod.Validation.Tests.cs b/lib/cycles/homod/tests/Homod.Validation.Tests.cs similarity index 100% rename from lib/cycles/homod/Homod.Validation.Tests.cs rename to lib/cycles/homod/tests/Homod.Validation.Tests.cs diff --git a/lib/cycles/ht_dcperiod/HtDcperiod.Quantower.Tests.cs b/lib/cycles/ht_dcperiod/tests/HtDcperiod.Quantower.Tests.cs similarity index 100% rename from lib/cycles/ht_dcperiod/HtDcperiod.Quantower.Tests.cs rename to lib/cycles/ht_dcperiod/tests/HtDcperiod.Quantower.Tests.cs diff --git a/lib/cycles/ht_dcperiod/HtDcperiod.Tests.cs b/lib/cycles/ht_dcperiod/tests/HtDcperiod.Tests.cs similarity index 100% rename from lib/cycles/ht_dcperiod/HtDcperiod.Tests.cs rename to lib/cycles/ht_dcperiod/tests/HtDcperiod.Tests.cs diff --git a/lib/cycles/ht_dcperiod/HtDcperiod.Validation.Tests.cs b/lib/cycles/ht_dcperiod/tests/HtDcperiod.Validation.Tests.cs similarity index 100% rename from lib/cycles/ht_dcperiod/HtDcperiod.Validation.Tests.cs rename to lib/cycles/ht_dcperiod/tests/HtDcperiod.Validation.Tests.cs diff --git a/lib/cycles/ht_dcphase/HtDcphase.Quantower.Tests.cs b/lib/cycles/ht_dcphase/tests/HtDcphase.Quantower.Tests.cs similarity index 100% rename from lib/cycles/ht_dcphase/HtDcphase.Quantower.Tests.cs rename to lib/cycles/ht_dcphase/tests/HtDcphase.Quantower.Tests.cs diff --git a/lib/cycles/ht_dcphase/HtDcphase.Tests.cs b/lib/cycles/ht_dcphase/tests/HtDcphase.Tests.cs similarity index 100% rename from lib/cycles/ht_dcphase/HtDcphase.Tests.cs rename to lib/cycles/ht_dcphase/tests/HtDcphase.Tests.cs diff --git a/lib/cycles/ht_dcphase/HtDcphase.Validation.Tests.cs b/lib/cycles/ht_dcphase/tests/HtDcphase.Validation.Tests.cs similarity index 100% rename from lib/cycles/ht_dcphase/HtDcphase.Validation.Tests.cs rename to lib/cycles/ht_dcphase/tests/HtDcphase.Validation.Tests.cs diff --git a/lib/cycles/ht_phasor/HtPhasor.Quantower.Tests.cs b/lib/cycles/ht_phasor/tests/HtPhasor.Quantower.Tests.cs similarity index 100% rename from lib/cycles/ht_phasor/HtPhasor.Quantower.Tests.cs rename to lib/cycles/ht_phasor/tests/HtPhasor.Quantower.Tests.cs diff --git a/lib/cycles/ht_phasor/HtPhasor.Tests.cs b/lib/cycles/ht_phasor/tests/HtPhasor.Tests.cs similarity index 100% rename from lib/cycles/ht_phasor/HtPhasor.Tests.cs rename to lib/cycles/ht_phasor/tests/HtPhasor.Tests.cs diff --git a/lib/cycles/ht_phasor/HtPhasor.Validation.Tests.cs b/lib/cycles/ht_phasor/tests/HtPhasor.Validation.Tests.cs similarity index 100% rename from lib/cycles/ht_phasor/HtPhasor.Validation.Tests.cs rename to lib/cycles/ht_phasor/tests/HtPhasor.Validation.Tests.cs diff --git a/lib/cycles/ht_sine/HtSine.Quantower.Tests.cs b/lib/cycles/ht_sine/tests/HtSine.Quantower.Tests.cs similarity index 100% rename from lib/cycles/ht_sine/HtSine.Quantower.Tests.cs rename to lib/cycles/ht_sine/tests/HtSine.Quantower.Tests.cs diff --git a/lib/cycles/ht_sine/HtSine.Tests.cs b/lib/cycles/ht_sine/tests/HtSine.Tests.cs similarity index 100% rename from lib/cycles/ht_sine/HtSine.Tests.cs rename to lib/cycles/ht_sine/tests/HtSine.Tests.cs diff --git a/lib/cycles/ht_sine/HtSine.Validation.Tests.cs b/lib/cycles/ht_sine/tests/HtSine.Validation.Tests.cs similarity index 100% rename from lib/cycles/ht_sine/HtSine.Validation.Tests.cs rename to lib/cycles/ht_sine/tests/HtSine.Validation.Tests.cs diff --git a/lib/cycles/lunar/Lunar.Quantower.Tests.cs b/lib/cycles/lunar/tests/Lunar.Quantower.Tests.cs similarity index 100% rename from lib/cycles/lunar/Lunar.Quantower.Tests.cs rename to lib/cycles/lunar/tests/Lunar.Quantower.Tests.cs diff --git a/lib/cycles/lunar/Lunar.Tests.cs b/lib/cycles/lunar/tests/Lunar.Tests.cs similarity index 100% rename from lib/cycles/lunar/Lunar.Tests.cs rename to lib/cycles/lunar/tests/Lunar.Tests.cs diff --git a/lib/cycles/lunar/Lunar.Validation.Tests.cs b/lib/cycles/lunar/tests/Lunar.Validation.Tests.cs similarity index 100% rename from lib/cycles/lunar/Lunar.Validation.Tests.cs rename to lib/cycles/lunar/tests/Lunar.Validation.Tests.cs diff --git a/lib/cycles/solar/Solar.Quantower.Tests.cs b/lib/cycles/solar/tests/Solar.Quantower.Tests.cs similarity index 100% rename from lib/cycles/solar/Solar.Quantower.Tests.cs rename to lib/cycles/solar/tests/Solar.Quantower.Tests.cs diff --git a/lib/cycles/solar/Solar.Tests.cs b/lib/cycles/solar/tests/Solar.Tests.cs similarity index 100% rename from lib/cycles/solar/Solar.Tests.cs rename to lib/cycles/solar/tests/Solar.Tests.cs diff --git a/lib/cycles/solar/Solar.Validation.Tests.cs b/lib/cycles/solar/tests/Solar.Validation.Tests.cs similarity index 100% rename from lib/cycles/solar/Solar.Validation.Tests.cs rename to lib/cycles/solar/tests/Solar.Validation.Tests.cs diff --git a/lib/cycles/ssfdsp/Ssfdsp.Quantower.Tests.cs b/lib/cycles/ssfdsp/tests/Ssfdsp.Quantower.Tests.cs similarity index 100% rename from lib/cycles/ssfdsp/Ssfdsp.Quantower.Tests.cs rename to lib/cycles/ssfdsp/tests/Ssfdsp.Quantower.Tests.cs diff --git a/lib/cycles/ssfdsp/Ssfdsp.Tests.cs b/lib/cycles/ssfdsp/tests/Ssfdsp.Tests.cs similarity index 100% rename from lib/cycles/ssfdsp/Ssfdsp.Tests.cs rename to lib/cycles/ssfdsp/tests/Ssfdsp.Tests.cs diff --git a/lib/cycles/ssfdsp/Ssfdsp.Validation.Tests.cs b/lib/cycles/ssfdsp/tests/Ssfdsp.Validation.Tests.cs similarity index 100% rename from lib/cycles/ssfdsp/Ssfdsp.Validation.Tests.cs rename to lib/cycles/ssfdsp/tests/Ssfdsp.Validation.Tests.cs diff --git a/lib/dynamics/adx/Adx.Quantower.Tests.cs b/lib/dynamics/adx/tests/Adx.Quantower.Tests.cs similarity index 100% rename from lib/dynamics/adx/Adx.Quantower.Tests.cs rename to lib/dynamics/adx/tests/Adx.Quantower.Tests.cs diff --git a/lib/dynamics/adx/Adx.Tests.cs b/lib/dynamics/adx/tests/Adx.Tests.cs similarity index 100% rename from lib/dynamics/adx/Adx.Tests.cs rename to lib/dynamics/adx/tests/Adx.Tests.cs diff --git a/lib/dynamics/adx/Adx.Validation.Tests.cs b/lib/dynamics/adx/tests/Adx.Validation.Tests.cs similarity index 100% rename from lib/dynamics/adx/Adx.Validation.Tests.cs rename to lib/dynamics/adx/tests/Adx.Validation.Tests.cs diff --git a/lib/dynamics/adxr/Adxr.Quantower.Tests.cs b/lib/dynamics/adxr/tests/Adxr.Quantower.Tests.cs similarity index 100% rename from lib/dynamics/adxr/Adxr.Quantower.Tests.cs rename to lib/dynamics/adxr/tests/Adxr.Quantower.Tests.cs diff --git a/lib/dynamics/adxr/Adxr.Tests.cs b/lib/dynamics/adxr/tests/Adxr.Tests.cs similarity index 100% rename from lib/dynamics/adxr/Adxr.Tests.cs rename to lib/dynamics/adxr/tests/Adxr.Tests.cs diff --git a/lib/dynamics/adxr/Adxr.Validation.Tests.cs b/lib/dynamics/adxr/tests/Adxr.Validation.Tests.cs similarity index 100% rename from lib/dynamics/adxr/Adxr.Validation.Tests.cs rename to lib/dynamics/adxr/tests/Adxr.Validation.Tests.cs diff --git a/lib/dynamics/alligator/Alligator.Quantower.Tests.cs b/lib/dynamics/alligator/tests/Alligator.Quantower.Tests.cs similarity index 100% rename from lib/dynamics/alligator/Alligator.Quantower.Tests.cs rename to lib/dynamics/alligator/tests/Alligator.Quantower.Tests.cs diff --git a/lib/dynamics/alligator/Alligator.Tests.cs b/lib/dynamics/alligator/tests/Alligator.Tests.cs similarity index 100% rename from lib/dynamics/alligator/Alligator.Tests.cs rename to lib/dynamics/alligator/tests/Alligator.Tests.cs diff --git a/lib/dynamics/alligator/Alligator.Validation.Tests.cs b/lib/dynamics/alligator/tests/Alligator.Validation.Tests.cs similarity index 100% rename from lib/dynamics/alligator/Alligator.Validation.Tests.cs rename to lib/dynamics/alligator/tests/Alligator.Validation.Tests.cs diff --git a/lib/dynamics/amat/Amat.Quantower.Tests.cs b/lib/dynamics/amat/tests/Amat.Quantower.Tests.cs similarity index 100% rename from lib/dynamics/amat/Amat.Quantower.Tests.cs rename to lib/dynamics/amat/tests/Amat.Quantower.Tests.cs diff --git a/lib/dynamics/amat/Amat.Tests.cs b/lib/dynamics/amat/tests/Amat.Tests.cs similarity index 100% rename from lib/dynamics/amat/Amat.Tests.cs rename to lib/dynamics/amat/tests/Amat.Tests.cs diff --git a/lib/dynamics/amat/Amat.Validation.Tests.cs b/lib/dynamics/amat/tests/Amat.Validation.Tests.cs similarity index 100% rename from lib/dynamics/amat/Amat.Validation.Tests.cs rename to lib/dynamics/amat/tests/Amat.Validation.Tests.cs diff --git a/lib/dynamics/aroon/Aroon.Quantower.Tests.cs b/lib/dynamics/aroon/tests/Aroon.Quantower.Tests.cs similarity index 100% rename from lib/dynamics/aroon/Aroon.Quantower.Tests.cs rename to lib/dynamics/aroon/tests/Aroon.Quantower.Tests.cs diff --git a/lib/dynamics/aroon/Aroon.Tests.cs b/lib/dynamics/aroon/tests/Aroon.Tests.cs similarity index 100% rename from lib/dynamics/aroon/Aroon.Tests.cs rename to lib/dynamics/aroon/tests/Aroon.Tests.cs diff --git a/lib/dynamics/aroon/Aroon.Validation.Tests.cs b/lib/dynamics/aroon/tests/Aroon.Validation.Tests.cs similarity index 100% rename from lib/dynamics/aroon/Aroon.Validation.Tests.cs rename to lib/dynamics/aroon/tests/Aroon.Validation.Tests.cs diff --git a/lib/dynamics/aroonosc/AroonOsc.Quantower.Tests.cs b/lib/dynamics/aroonosc/tests/AroonOsc.Quantower.Tests.cs similarity index 100% rename from lib/dynamics/aroonosc/AroonOsc.Quantower.Tests.cs rename to lib/dynamics/aroonosc/tests/AroonOsc.Quantower.Tests.cs diff --git a/lib/dynamics/aroonosc/AroonOsc.Tests.cs b/lib/dynamics/aroonosc/tests/AroonOsc.Tests.cs similarity index 100% rename from lib/dynamics/aroonosc/AroonOsc.Tests.cs rename to lib/dynamics/aroonosc/tests/AroonOsc.Tests.cs diff --git a/lib/dynamics/aroonosc/AroonOsc.Validation.Tests.cs b/lib/dynamics/aroonosc/tests/AroonOsc.Validation.Tests.cs similarity index 100% rename from lib/dynamics/aroonosc/AroonOsc.Validation.Tests.cs rename to lib/dynamics/aroonosc/tests/AroonOsc.Validation.Tests.cs diff --git a/lib/dynamics/chop/Chop.Quantower.Tests.cs b/lib/dynamics/chop/tests/Chop.Quantower.Tests.cs similarity index 100% rename from lib/dynamics/chop/Chop.Quantower.Tests.cs rename to lib/dynamics/chop/tests/Chop.Quantower.Tests.cs diff --git a/lib/dynamics/chop/Chop.Tests.cs b/lib/dynamics/chop/tests/Chop.Tests.cs similarity index 100% rename from lib/dynamics/chop/Chop.Tests.cs rename to lib/dynamics/chop/tests/Chop.Tests.cs diff --git a/lib/dynamics/chop/Chop.Validation.Tests.cs b/lib/dynamics/chop/tests/Chop.Validation.Tests.cs similarity index 100% rename from lib/dynamics/chop/Chop.Validation.Tests.cs rename to lib/dynamics/chop/tests/Chop.Validation.Tests.cs diff --git a/lib/dynamics/dmx/Dmx.Quantower.Tests.cs b/lib/dynamics/dmx/tests/Dmx.Quantower.Tests.cs similarity index 100% rename from lib/dynamics/dmx/Dmx.Quantower.Tests.cs rename to lib/dynamics/dmx/tests/Dmx.Quantower.Tests.cs diff --git a/lib/dynamics/dmx/Dmx.Tests.cs b/lib/dynamics/dmx/tests/Dmx.Tests.cs similarity index 100% rename from lib/dynamics/dmx/Dmx.Tests.cs rename to lib/dynamics/dmx/tests/Dmx.Tests.cs diff --git a/lib/dynamics/dmx/Dmx.Validation.Tests.cs b/lib/dynamics/dmx/tests/Dmx.Validation.Tests.cs similarity index 100% rename from lib/dynamics/dmx/Dmx.Validation.Tests.cs rename to lib/dynamics/dmx/tests/Dmx.Validation.Tests.cs diff --git a/lib/dynamics/dx/Dx.Quantower.Tests.cs b/lib/dynamics/dx/tests/Dx.Quantower.Tests.cs similarity index 100% rename from lib/dynamics/dx/Dx.Quantower.Tests.cs rename to lib/dynamics/dx/tests/Dx.Quantower.Tests.cs diff --git a/lib/dynamics/dx/Dx.Tests.cs b/lib/dynamics/dx/tests/Dx.Tests.cs similarity index 100% rename from lib/dynamics/dx/Dx.Tests.cs rename to lib/dynamics/dx/tests/Dx.Tests.cs diff --git a/lib/dynamics/dx/Dx.Validation.Tests.cs b/lib/dynamics/dx/tests/Dx.Validation.Tests.cs similarity index 100% rename from lib/dynamics/dx/Dx.Validation.Tests.cs rename to lib/dynamics/dx/tests/Dx.Validation.Tests.cs diff --git a/lib/dynamics/ghla/Ghla.Quantower.Tests.cs b/lib/dynamics/ghla/tests/Ghla.Quantower.Tests.cs similarity index 100% rename from lib/dynamics/ghla/Ghla.Quantower.Tests.cs rename to lib/dynamics/ghla/tests/Ghla.Quantower.Tests.cs diff --git a/lib/dynamics/ghla/Ghla.Tests.cs b/lib/dynamics/ghla/tests/Ghla.Tests.cs similarity index 100% rename from lib/dynamics/ghla/Ghla.Tests.cs rename to lib/dynamics/ghla/tests/Ghla.Tests.cs diff --git a/lib/dynamics/ghla/Ghla.Validation.Tests.cs b/lib/dynamics/ghla/tests/Ghla.Validation.Tests.cs similarity index 100% rename from lib/dynamics/ghla/Ghla.Validation.Tests.cs rename to lib/dynamics/ghla/tests/Ghla.Validation.Tests.cs diff --git a/lib/dynamics/ht_trendmode/HtTrendmode.Quantower.Tests.cs b/lib/dynamics/ht_trendmode/tests/HtTrendmode.Quantower.Tests.cs similarity index 100% rename from lib/dynamics/ht_trendmode/HtTrendmode.Quantower.Tests.cs rename to lib/dynamics/ht_trendmode/tests/HtTrendmode.Quantower.Tests.cs diff --git a/lib/dynamics/ht_trendmode/HtTrendmode.Tests.cs b/lib/dynamics/ht_trendmode/tests/HtTrendmode.Tests.cs similarity index 100% rename from lib/dynamics/ht_trendmode/HtTrendmode.Tests.cs rename to lib/dynamics/ht_trendmode/tests/HtTrendmode.Tests.cs diff --git a/lib/dynamics/ht_trendmode/HtTrendmode.Validation.Tests.cs b/lib/dynamics/ht_trendmode/tests/HtTrendmode.Validation.Tests.cs similarity index 100% rename from lib/dynamics/ht_trendmode/HtTrendmode.Validation.Tests.cs rename to lib/dynamics/ht_trendmode/tests/HtTrendmode.Validation.Tests.cs diff --git a/lib/dynamics/ichimoku/Ichimoku.Quantower.Tests.cs b/lib/dynamics/ichimoku/tests/Ichimoku.Quantower.Tests.cs similarity index 100% rename from lib/dynamics/ichimoku/Ichimoku.Quantower.Tests.cs rename to lib/dynamics/ichimoku/tests/Ichimoku.Quantower.Tests.cs diff --git a/lib/dynamics/ichimoku/Ichimoku.Tests.cs b/lib/dynamics/ichimoku/tests/Ichimoku.Tests.cs similarity index 100% rename from lib/dynamics/ichimoku/Ichimoku.Tests.cs rename to lib/dynamics/ichimoku/tests/Ichimoku.Tests.cs diff --git a/lib/dynamics/ichimoku/Ichimoku.Validation.Tests.cs b/lib/dynamics/ichimoku/tests/Ichimoku.Validation.Tests.cs similarity index 100% rename from lib/dynamics/ichimoku/Ichimoku.Validation.Tests.cs rename to lib/dynamics/ichimoku/tests/Ichimoku.Validation.Tests.cs diff --git a/lib/dynamics/impulse/Impulse.Quantower.Tests.cs b/lib/dynamics/impulse/tests/Impulse.Quantower.Tests.cs similarity index 100% rename from lib/dynamics/impulse/Impulse.Quantower.Tests.cs rename to lib/dynamics/impulse/tests/Impulse.Quantower.Tests.cs diff --git a/lib/dynamics/impulse/Impulse.Tests.cs b/lib/dynamics/impulse/tests/Impulse.Tests.cs similarity index 100% rename from lib/dynamics/impulse/Impulse.Tests.cs rename to lib/dynamics/impulse/tests/Impulse.Tests.cs diff --git a/lib/dynamics/impulse/Impulse.Validation.Tests.cs b/lib/dynamics/impulse/tests/Impulse.Validation.Tests.cs similarity index 100% rename from lib/dynamics/impulse/Impulse.Validation.Tests.cs rename to lib/dynamics/impulse/tests/Impulse.Validation.Tests.cs diff --git a/lib/dynamics/minusdi/MinusDi.Quantower.Tests.cs b/lib/dynamics/minusdi/tests/MinusDi.Quantower.Tests.cs similarity index 100% rename from lib/dynamics/minusdi/MinusDi.Quantower.Tests.cs rename to lib/dynamics/minusdi/tests/MinusDi.Quantower.Tests.cs diff --git a/lib/dynamics/minusdi/MinusDi.Validation.Tests.cs b/lib/dynamics/minusdi/tests/MinusDi.Validation.Tests.cs similarity index 100% rename from lib/dynamics/minusdi/MinusDi.Validation.Tests.cs rename to lib/dynamics/minusdi/tests/MinusDi.Validation.Tests.cs diff --git a/lib/dynamics/minusdm/MinusDm.Quantower.Tests.cs b/lib/dynamics/minusdm/tests/MinusDm.Quantower.Tests.cs similarity index 100% rename from lib/dynamics/minusdm/MinusDm.Quantower.Tests.cs rename to lib/dynamics/minusdm/tests/MinusDm.Quantower.Tests.cs diff --git a/lib/dynamics/minusdm/MinusDm.Validation.Tests.cs b/lib/dynamics/minusdm/tests/MinusDm.Validation.Tests.cs similarity index 100% rename from lib/dynamics/minusdm/MinusDm.Validation.Tests.cs rename to lib/dynamics/minusdm/tests/MinusDm.Validation.Tests.cs diff --git a/lib/dynamics/pfe/Pfe.Quantower.Tests.cs b/lib/dynamics/pfe/tests/Pfe.Quantower.Tests.cs similarity index 100% rename from lib/dynamics/pfe/Pfe.Quantower.Tests.cs rename to lib/dynamics/pfe/tests/Pfe.Quantower.Tests.cs diff --git a/lib/dynamics/pfe/Pfe.Tests.cs b/lib/dynamics/pfe/tests/Pfe.Tests.cs similarity index 100% rename from lib/dynamics/pfe/Pfe.Tests.cs rename to lib/dynamics/pfe/tests/Pfe.Tests.cs diff --git a/lib/dynamics/pfe/Pfe.Validation.Tests.cs b/lib/dynamics/pfe/tests/Pfe.Validation.Tests.cs similarity index 100% rename from lib/dynamics/pfe/Pfe.Validation.Tests.cs rename to lib/dynamics/pfe/tests/Pfe.Validation.Tests.cs diff --git a/lib/dynamics/plusdi/DiDm.Tests.cs b/lib/dynamics/plusdi/tests/DiDm.Tests.cs similarity index 100% rename from lib/dynamics/plusdi/DiDm.Tests.cs rename to lib/dynamics/plusdi/tests/DiDm.Tests.cs diff --git a/lib/dynamics/plusdi/DiDm.Validation.Tests.cs b/lib/dynamics/plusdi/tests/DiDm.Validation.Tests.cs similarity index 100% rename from lib/dynamics/plusdi/DiDm.Validation.Tests.cs rename to lib/dynamics/plusdi/tests/DiDm.Validation.Tests.cs diff --git a/lib/dynamics/plusdi/PlusDi.Quantower.Tests.cs b/lib/dynamics/plusdi/tests/PlusDi.Quantower.Tests.cs similarity index 100% rename from lib/dynamics/plusdi/PlusDi.Quantower.Tests.cs rename to lib/dynamics/plusdi/tests/PlusDi.Quantower.Tests.cs diff --git a/lib/dynamics/plusdi/PlusDi.Validation.Tests.cs b/lib/dynamics/plusdi/tests/PlusDi.Validation.Tests.cs similarity index 100% rename from lib/dynamics/plusdi/PlusDi.Validation.Tests.cs rename to lib/dynamics/plusdi/tests/PlusDi.Validation.Tests.cs diff --git a/lib/dynamics/plusdm/PlusDm.Quantower.Tests.cs b/lib/dynamics/plusdm/tests/PlusDm.Quantower.Tests.cs similarity index 100% rename from lib/dynamics/plusdm/PlusDm.Quantower.Tests.cs rename to lib/dynamics/plusdm/tests/PlusDm.Quantower.Tests.cs diff --git a/lib/dynamics/plusdm/PlusDm.Validation.Tests.cs b/lib/dynamics/plusdm/tests/PlusDm.Validation.Tests.cs similarity index 100% rename from lib/dynamics/plusdm/PlusDm.Validation.Tests.cs rename to lib/dynamics/plusdm/tests/PlusDm.Validation.Tests.cs diff --git a/lib/dynamics/qstick/Qstick.Quantower.Tests.cs b/lib/dynamics/qstick/tests/Qstick.Quantower.Tests.cs similarity index 100% rename from lib/dynamics/qstick/Qstick.Quantower.Tests.cs rename to lib/dynamics/qstick/tests/Qstick.Quantower.Tests.cs diff --git a/lib/dynamics/qstick/Qstick.Tests.cs b/lib/dynamics/qstick/tests/Qstick.Tests.cs similarity index 100% rename from lib/dynamics/qstick/Qstick.Tests.cs rename to lib/dynamics/qstick/tests/Qstick.Tests.cs diff --git a/lib/dynamics/qstick/Qstick.Validation.Tests.cs b/lib/dynamics/qstick/tests/Qstick.Validation.Tests.cs similarity index 100% rename from lib/dynamics/qstick/Qstick.Validation.Tests.cs rename to lib/dynamics/qstick/tests/Qstick.Validation.Tests.cs diff --git a/lib/dynamics/ravi/Ravi.Quantower.Tests.cs b/lib/dynamics/ravi/tests/Ravi.Quantower.Tests.cs similarity index 100% rename from lib/dynamics/ravi/Ravi.Quantower.Tests.cs rename to lib/dynamics/ravi/tests/Ravi.Quantower.Tests.cs diff --git a/lib/dynamics/ravi/Ravi.Tests.cs b/lib/dynamics/ravi/tests/Ravi.Tests.cs similarity index 100% rename from lib/dynamics/ravi/Ravi.Tests.cs rename to lib/dynamics/ravi/tests/Ravi.Tests.cs diff --git a/lib/dynamics/ravi/Ravi.Validation.Tests.cs b/lib/dynamics/ravi/tests/Ravi.Validation.Tests.cs similarity index 100% rename from lib/dynamics/ravi/Ravi.Validation.Tests.cs rename to lib/dynamics/ravi/tests/Ravi.Validation.Tests.cs diff --git a/lib/dynamics/super/Super.Quantower.Tests.cs b/lib/dynamics/super/tests/Super.Quantower.Tests.cs similarity index 100% rename from lib/dynamics/super/Super.Quantower.Tests.cs rename to lib/dynamics/super/tests/Super.Quantower.Tests.cs diff --git a/lib/dynamics/super/Super.Tests.cs b/lib/dynamics/super/tests/Super.Tests.cs similarity index 100% rename from lib/dynamics/super/Super.Tests.cs rename to lib/dynamics/super/tests/Super.Tests.cs diff --git a/lib/dynamics/super/Super.Validation.Tests.cs b/lib/dynamics/super/tests/Super.Validation.Tests.cs similarity index 100% rename from lib/dynamics/super/Super.Validation.Tests.cs rename to lib/dynamics/super/tests/Super.Validation.Tests.cs diff --git a/lib/dynamics/ttm_squeeze/TtmSqueeze.Quantower.Tests.cs b/lib/dynamics/ttm_squeeze/tests/TtmSqueeze.Quantower.Tests.cs similarity index 100% rename from lib/dynamics/ttm_squeeze/TtmSqueeze.Quantower.Tests.cs rename to lib/dynamics/ttm_squeeze/tests/TtmSqueeze.Quantower.Tests.cs diff --git a/lib/dynamics/ttm_squeeze/TtmSqueeze.Tests.cs b/lib/dynamics/ttm_squeeze/tests/TtmSqueeze.Tests.cs similarity index 100% rename from lib/dynamics/ttm_squeeze/TtmSqueeze.Tests.cs rename to lib/dynamics/ttm_squeeze/tests/TtmSqueeze.Tests.cs diff --git a/lib/dynamics/ttm_squeeze/TtmSqueeze.Validation.Tests.cs b/lib/dynamics/ttm_squeeze/tests/TtmSqueeze.Validation.Tests.cs similarity index 100% rename from lib/dynamics/ttm_squeeze/TtmSqueeze.Validation.Tests.cs rename to lib/dynamics/ttm_squeeze/tests/TtmSqueeze.Validation.Tests.cs diff --git a/lib/dynamics/ttm_trend/TtmTrend.Quantower.Tests.cs b/lib/dynamics/ttm_trend/tests/TtmTrend.Quantower.Tests.cs similarity index 100% rename from lib/dynamics/ttm_trend/TtmTrend.Quantower.Tests.cs rename to lib/dynamics/ttm_trend/tests/TtmTrend.Quantower.Tests.cs diff --git a/lib/dynamics/ttm_trend/TtmTrend.Tests.cs b/lib/dynamics/ttm_trend/tests/TtmTrend.Tests.cs similarity index 100% rename from lib/dynamics/ttm_trend/TtmTrend.Tests.cs rename to lib/dynamics/ttm_trend/tests/TtmTrend.Tests.cs diff --git a/lib/dynamics/ttm_trend/TtmTrend.Validation.Tests.cs b/lib/dynamics/ttm_trend/tests/TtmTrend.Validation.Tests.cs similarity index 100% rename from lib/dynamics/ttm_trend/TtmTrend.Validation.Tests.cs rename to lib/dynamics/ttm_trend/tests/TtmTrend.Validation.Tests.cs diff --git a/lib/dynamics/vhf/Vhf.Quantower.Tests.cs b/lib/dynamics/vhf/tests/Vhf.Quantower.Tests.cs similarity index 100% rename from lib/dynamics/vhf/Vhf.Quantower.Tests.cs rename to lib/dynamics/vhf/tests/Vhf.Quantower.Tests.cs diff --git a/lib/dynamics/vhf/Vhf.Tests.cs b/lib/dynamics/vhf/tests/Vhf.Tests.cs similarity index 99% rename from lib/dynamics/vhf/Vhf.Tests.cs rename to lib/dynamics/vhf/tests/Vhf.Tests.cs index 41fa4101..10aa3ee7 100644 --- a/lib/dynamics/vhf/Vhf.Tests.cs +++ b/lib/dynamics/vhf/tests/Vhf.Tests.cs @@ -149,7 +149,7 @@ public class VhfTests public void Calc_IsNew_False_UpdatesValue() { var vhf = new Vhf(5); - var gbm = new GBM(startPrice: 100.0); + var gbm = new GBM(startPrice: 100.0, mu: 0.05, sigma: 0.2, seed: 42); var bars = gbm.Fetch(20, DateTime.UtcNow.Ticks, TimeSpan.FromMinutes(1)); // Feed 10 bars to get past warmup diff --git a/lib/dynamics/vhf/Vhf.Validation.Tests.cs b/lib/dynamics/vhf/tests/Vhf.Validation.Tests.cs similarity index 100% rename from lib/dynamics/vhf/Vhf.Validation.Tests.cs rename to lib/dynamics/vhf/tests/Vhf.Validation.Tests.cs diff --git a/lib/dynamics/vortex/Vortex.Quantower.Tests.cs b/lib/dynamics/vortex/tests/Vortex.Quantower.Tests.cs similarity index 100% rename from lib/dynamics/vortex/Vortex.Quantower.Tests.cs rename to lib/dynamics/vortex/tests/Vortex.Quantower.Tests.cs diff --git a/lib/dynamics/vortex/Vortex.Tests.cs b/lib/dynamics/vortex/tests/Vortex.Tests.cs similarity index 100% rename from lib/dynamics/vortex/Vortex.Tests.cs rename to lib/dynamics/vortex/tests/Vortex.Tests.cs diff --git a/lib/dynamics/vortex/Vortex.Validation.Tests.cs b/lib/dynamics/vortex/tests/Vortex.Validation.Tests.cs similarity index 100% rename from lib/dynamics/vortex/Vortex.Validation.Tests.cs rename to lib/dynamics/vortex/tests/Vortex.Validation.Tests.cs diff --git a/lib/errors/huber/Huber.Tests.cs b/lib/errors/huber/tests/Huber.Tests.cs similarity index 100% rename from lib/errors/huber/Huber.Tests.cs rename to lib/errors/huber/tests/Huber.Tests.cs diff --git a/lib/errors/logcosh/LogCosh.Tests.cs b/lib/errors/logcosh/tests/LogCosh.Tests.cs similarity index 100% rename from lib/errors/logcosh/LogCosh.Tests.cs rename to lib/errors/logcosh/tests/LogCosh.Tests.cs diff --git a/lib/errors/maape/Maape.Tests.cs b/lib/errors/maape/tests/Maape.Tests.cs similarity index 100% rename from lib/errors/maape/Maape.Tests.cs rename to lib/errors/maape/tests/Maape.Tests.cs diff --git a/lib/errors/mae/Mae.Tests.cs b/lib/errors/mae/tests/Mae.Tests.cs similarity index 100% rename from lib/errors/mae/Mae.Tests.cs rename to lib/errors/mae/tests/Mae.Tests.cs diff --git a/lib/errors/mae/Mae.Validation.Tests.cs b/lib/errors/mae/tests/Mae.Validation.Tests.cs similarity index 100% rename from lib/errors/mae/Mae.Validation.Tests.cs rename to lib/errors/mae/tests/Mae.Validation.Tests.cs diff --git a/lib/errors/mapd/Mapd.Tests.cs b/lib/errors/mapd/tests/Mapd.Tests.cs similarity index 100% rename from lib/errors/mapd/Mapd.Tests.cs rename to lib/errors/mapd/tests/Mapd.Tests.cs diff --git a/lib/errors/mape/Mape.Tests.cs b/lib/errors/mape/tests/Mape.Tests.cs similarity index 100% rename from lib/errors/mape/Mape.Tests.cs rename to lib/errors/mape/tests/Mape.Tests.cs diff --git a/lib/errors/mape/Mape.Validation.Tests.cs b/lib/errors/mape/tests/Mape.Validation.Tests.cs similarity index 100% rename from lib/errors/mape/Mape.Validation.Tests.cs rename to lib/errors/mape/tests/Mape.Validation.Tests.cs diff --git a/lib/errors/mase/Mase.Tests.cs b/lib/errors/mase/tests/Mase.Tests.cs similarity index 100% rename from lib/errors/mase/Mase.Tests.cs rename to lib/errors/mase/tests/Mase.Tests.cs diff --git a/lib/errors/mdae/Mdae.Tests.cs b/lib/errors/mdae/tests/Mdae.Tests.cs similarity index 100% rename from lib/errors/mdae/Mdae.Tests.cs rename to lib/errors/mdae/tests/Mdae.Tests.cs diff --git a/lib/errors/mdape/Mdape.Tests.cs b/lib/errors/mdape/tests/Mdape.Tests.cs similarity index 100% rename from lib/errors/mdape/Mdape.Tests.cs rename to lib/errors/mdape/tests/Mdape.Tests.cs diff --git a/lib/errors/me/Me.Tests.cs b/lib/errors/me/tests/Me.Tests.cs similarity index 100% rename from lib/errors/me/Me.Tests.cs rename to lib/errors/me/tests/Me.Tests.cs diff --git a/lib/errors/mpe/Mpe.Tests.cs b/lib/errors/mpe/tests/Mpe.Tests.cs similarity index 100% rename from lib/errors/mpe/Mpe.Tests.cs rename to lib/errors/mpe/tests/Mpe.Tests.cs diff --git a/lib/errors/mrae/Mrae.Tests.cs b/lib/errors/mrae/tests/Mrae.Tests.cs similarity index 100% rename from lib/errors/mrae/Mrae.Tests.cs rename to lib/errors/mrae/tests/Mrae.Tests.cs diff --git a/lib/errors/mse/Mse.Tests.cs b/lib/errors/mse/tests/Mse.Tests.cs similarity index 100% rename from lib/errors/mse/Mse.Tests.cs rename to lib/errors/mse/tests/Mse.Tests.cs diff --git a/lib/errors/mse/Mse.Validation.Tests.cs b/lib/errors/mse/tests/Mse.Validation.Tests.cs similarity index 100% rename from lib/errors/mse/Mse.Validation.Tests.cs rename to lib/errors/mse/tests/Mse.Validation.Tests.cs diff --git a/lib/errors/msle/Msle.Tests.cs b/lib/errors/msle/tests/Msle.Tests.cs similarity index 100% rename from lib/errors/msle/Msle.Tests.cs rename to lib/errors/msle/tests/Msle.Tests.cs diff --git a/lib/errors/pseudohuber/PseudoHuber.Tests.cs b/lib/errors/pseudohuber/tests/PseudoHuber.Tests.cs similarity index 100% rename from lib/errors/pseudohuber/PseudoHuber.Tests.cs rename to lib/errors/pseudohuber/tests/PseudoHuber.Tests.cs diff --git a/lib/errors/quantileloss/QuantileLoss.Tests.cs b/lib/errors/quantileloss/tests/QuantileLoss.Tests.cs similarity index 100% rename from lib/errors/quantileloss/QuantileLoss.Tests.cs rename to lib/errors/quantileloss/tests/QuantileLoss.Tests.cs diff --git a/lib/errors/rae/Rae.Tests.cs b/lib/errors/rae/tests/Rae.Tests.cs similarity index 100% rename from lib/errors/rae/Rae.Tests.cs rename to lib/errors/rae/tests/Rae.Tests.cs diff --git a/lib/errors/rmse/Rmse.Tests.cs b/lib/errors/rmse/tests/Rmse.Tests.cs similarity index 100% rename from lib/errors/rmse/Rmse.Tests.cs rename to lib/errors/rmse/tests/Rmse.Tests.cs diff --git a/lib/errors/rmse/Rmse.Validation.Tests.cs b/lib/errors/rmse/tests/Rmse.Validation.Tests.cs similarity index 100% rename from lib/errors/rmse/Rmse.Validation.Tests.cs rename to lib/errors/rmse/tests/Rmse.Validation.Tests.cs diff --git a/lib/errors/rmsle/Rmsle.Tests.cs b/lib/errors/rmsle/tests/Rmsle.Tests.cs similarity index 100% rename from lib/errors/rmsle/Rmsle.Tests.cs rename to lib/errors/rmsle/tests/Rmsle.Tests.cs diff --git a/lib/errors/rse/Rse.Tests.cs b/lib/errors/rse/tests/Rse.Tests.cs similarity index 100% rename from lib/errors/rse/Rse.Tests.cs rename to lib/errors/rse/tests/Rse.Tests.cs diff --git a/lib/errors/rsquared/Rsquared.Tests.cs b/lib/errors/rsquared/tests/Rsquared.Tests.cs similarity index 100% rename from lib/errors/rsquared/Rsquared.Tests.cs rename to lib/errors/rsquared/tests/Rsquared.Tests.cs diff --git a/lib/errors/rsquared/Rsquared.Validation.Tests.cs b/lib/errors/rsquared/tests/Rsquared.Validation.Tests.cs similarity index 100% rename from lib/errors/rsquared/Rsquared.Validation.Tests.cs rename to lib/errors/rsquared/tests/Rsquared.Validation.Tests.cs diff --git a/lib/errors/smape/Smape.Tests.cs b/lib/errors/smape/tests/Smape.Tests.cs similarity index 100% rename from lib/errors/smape/Smape.Tests.cs rename to lib/errors/smape/tests/Smape.Tests.cs diff --git a/lib/errors/theilu/TheilU.Tests.cs b/lib/errors/theilu/tests/TheilU.Tests.cs similarity index 100% rename from lib/errors/theilu/TheilU.Tests.cs rename to lib/errors/theilu/tests/TheilU.Tests.cs diff --git a/lib/errors/tukeybiweight/TukeyBiweight.Tests.cs b/lib/errors/tukeybiweight/tests/TukeyBiweight.Tests.cs similarity index 100% rename from lib/errors/tukeybiweight/TukeyBiweight.Tests.cs rename to lib/errors/tukeybiweight/tests/TukeyBiweight.Tests.cs diff --git a/lib/errors/wmape/Wmape.Tests.cs b/lib/errors/wmape/tests/Wmape.Tests.cs similarity index 100% rename from lib/errors/wmape/Wmape.Tests.cs rename to lib/errors/wmape/tests/Wmape.Tests.cs diff --git a/lib/errors/wrmse/Wrmse.Tests.cs b/lib/errors/wrmse/tests/Wrmse.Tests.cs similarity index 100% rename from lib/errors/wrmse/Wrmse.Tests.cs rename to lib/errors/wrmse/tests/Wrmse.Tests.cs diff --git a/lib/feeds/csvfeed/CsvFeed.Tests.cs b/lib/feeds/csvfeed/tests/CsvFeed.Tests.cs similarity index 100% rename from lib/feeds/csvfeed/CsvFeed.Tests.cs rename to lib/feeds/csvfeed/tests/CsvFeed.Tests.cs diff --git a/lib/feeds/gbm/Gbm.Tests.cs b/lib/feeds/gbm/tests/Gbm.Tests.cs similarity index 100% rename from lib/feeds/gbm/Gbm.Tests.cs rename to lib/feeds/gbm/tests/Gbm.Tests.cs diff --git a/lib/filters/agc/Agc.Quantower.Tests.cs b/lib/filters/agc/tests/Agc.Quantower.Tests.cs similarity index 100% rename from lib/filters/agc/Agc.Quantower.Tests.cs rename to lib/filters/agc/tests/Agc.Quantower.Tests.cs diff --git a/lib/filters/agc/Agc.Tests.cs b/lib/filters/agc/tests/Agc.Tests.cs similarity index 100% rename from lib/filters/agc/Agc.Tests.cs rename to lib/filters/agc/tests/Agc.Tests.cs diff --git a/lib/filters/agc/Agc.Validation.Tests.cs b/lib/filters/agc/tests/Agc.Validation.Tests.cs similarity index 100% rename from lib/filters/agc/Agc.Validation.Tests.cs rename to lib/filters/agc/tests/Agc.Validation.Tests.cs diff --git a/lib/filters/alaguerre/ALaguerre.Quantower.Tests.cs b/lib/filters/alaguerre/tests/ALaguerre.Quantower.Tests.cs similarity index 100% rename from lib/filters/alaguerre/ALaguerre.Quantower.Tests.cs rename to lib/filters/alaguerre/tests/ALaguerre.Quantower.Tests.cs diff --git a/lib/filters/alaguerre/ALaguerre.Tests.cs b/lib/filters/alaguerre/tests/ALaguerre.Tests.cs similarity index 100% rename from lib/filters/alaguerre/ALaguerre.Tests.cs rename to lib/filters/alaguerre/tests/ALaguerre.Tests.cs diff --git a/lib/filters/alaguerre/ALaguerre.Validation.Tests.cs b/lib/filters/alaguerre/tests/ALaguerre.Validation.Tests.cs similarity index 100% rename from lib/filters/alaguerre/ALaguerre.Validation.Tests.cs rename to lib/filters/alaguerre/tests/ALaguerre.Validation.Tests.cs diff --git a/lib/filters/baxterking/BaxterKing.Quantower.Tests.cs b/lib/filters/baxterking/tests/BaxterKing.Quantower.Tests.cs similarity index 100% rename from lib/filters/baxterking/BaxterKing.Quantower.Tests.cs rename to lib/filters/baxterking/tests/BaxterKing.Quantower.Tests.cs diff --git a/lib/filters/baxterking/BaxterKing.Tests.cs b/lib/filters/baxterking/tests/BaxterKing.Tests.cs similarity index 100% rename from lib/filters/baxterking/BaxterKing.Tests.cs rename to lib/filters/baxterking/tests/BaxterKing.Tests.cs diff --git a/lib/filters/baxterking/BaxterKing.Validation.Tests.cs b/lib/filters/baxterking/tests/BaxterKing.Validation.Tests.cs similarity index 100% rename from lib/filters/baxterking/BaxterKing.Validation.Tests.cs rename to lib/filters/baxterking/tests/BaxterKing.Validation.Tests.cs diff --git a/lib/filters/bessel/Bessel.Quantower.Tests.cs b/lib/filters/bessel/tests/Bessel.Quantower.Tests.cs similarity index 100% rename from lib/filters/bessel/Bessel.Quantower.Tests.cs rename to lib/filters/bessel/tests/Bessel.Quantower.Tests.cs diff --git a/lib/filters/bessel/Bessel.Tests.cs b/lib/filters/bessel/tests/Bessel.Tests.cs similarity index 100% rename from lib/filters/bessel/Bessel.Tests.cs rename to lib/filters/bessel/tests/Bessel.Tests.cs diff --git a/lib/filters/bessel/Bessel.Validation.Tests.cs b/lib/filters/bessel/tests/Bessel.Validation.Tests.cs similarity index 100% rename from lib/filters/bessel/Bessel.Validation.Tests.cs rename to lib/filters/bessel/tests/Bessel.Validation.Tests.cs diff --git a/lib/filters/bilateral/Bilateral.Quantower.Tests.cs b/lib/filters/bilateral/tests/Bilateral.Quantower.Tests.cs similarity index 100% rename from lib/filters/bilateral/Bilateral.Quantower.Tests.cs rename to lib/filters/bilateral/tests/Bilateral.Quantower.Tests.cs diff --git a/lib/filters/bilateral/Bilateral.Tests.cs b/lib/filters/bilateral/tests/Bilateral.Tests.cs similarity index 100% rename from lib/filters/bilateral/Bilateral.Tests.cs rename to lib/filters/bilateral/tests/Bilateral.Tests.cs diff --git a/lib/filters/bilateral/Bilateral.Validation.Tests.cs b/lib/filters/bilateral/tests/Bilateral.Validation.Tests.cs similarity index 100% rename from lib/filters/bilateral/Bilateral.Validation.Tests.cs rename to lib/filters/bilateral/tests/Bilateral.Validation.Tests.cs diff --git a/lib/filters/bpf/Bpf.Quantower.Tests.cs b/lib/filters/bpf/tests/Bpf.Quantower.Tests.cs similarity index 100% rename from lib/filters/bpf/Bpf.Quantower.Tests.cs rename to lib/filters/bpf/tests/Bpf.Quantower.Tests.cs diff --git a/lib/filters/bpf/Bpf.Tests.cs b/lib/filters/bpf/tests/Bpf.Tests.cs similarity index 100% rename from lib/filters/bpf/Bpf.Tests.cs rename to lib/filters/bpf/tests/Bpf.Tests.cs diff --git a/lib/filters/bpf/Bpf.Validation.Tests.cs b/lib/filters/bpf/tests/Bpf.Validation.Tests.cs similarity index 100% rename from lib/filters/bpf/Bpf.Validation.Tests.cs rename to lib/filters/bpf/tests/Bpf.Validation.Tests.cs diff --git a/lib/filters/butter2/Butter2.Quantower.Tests.cs b/lib/filters/butter2/tests/Butter2.Quantower.Tests.cs similarity index 100% rename from lib/filters/butter2/Butter2.Quantower.Tests.cs rename to lib/filters/butter2/tests/Butter2.Quantower.Tests.cs diff --git a/lib/filters/butter2/Butter2.Tests.cs b/lib/filters/butter2/tests/Butter2.Tests.cs similarity index 100% rename from lib/filters/butter2/Butter2.Tests.cs rename to lib/filters/butter2/tests/Butter2.Tests.cs diff --git a/lib/filters/butter2/Butter2.Validation.Tests.cs b/lib/filters/butter2/tests/Butter2.Validation.Tests.cs similarity index 100% rename from lib/filters/butter2/Butter2.Validation.Tests.cs rename to lib/filters/butter2/tests/Butter2.Validation.Tests.cs diff --git a/lib/filters/butter3/Butter3.Quantower.Tests.cs b/lib/filters/butter3/tests/Butter3.Quantower.Tests.cs similarity index 100% rename from lib/filters/butter3/Butter3.Quantower.Tests.cs rename to lib/filters/butter3/tests/Butter3.Quantower.Tests.cs diff --git a/lib/filters/butter3/Butter3.Tests.cs b/lib/filters/butter3/tests/Butter3.Tests.cs similarity index 100% rename from lib/filters/butter3/Butter3.Tests.cs rename to lib/filters/butter3/tests/Butter3.Tests.cs diff --git a/lib/filters/butter3/Butter3.Validation.Tests.cs b/lib/filters/butter3/tests/Butter3.Validation.Tests.cs similarity index 100% rename from lib/filters/butter3/Butter3.Validation.Tests.cs rename to lib/filters/butter3/tests/Butter3.Validation.Tests.cs diff --git a/lib/filters/cfitz/Cfitz.Quantower.Tests.cs b/lib/filters/cfitz/tests/Cfitz.Quantower.Tests.cs similarity index 100% rename from lib/filters/cfitz/Cfitz.Quantower.Tests.cs rename to lib/filters/cfitz/tests/Cfitz.Quantower.Tests.cs diff --git a/lib/filters/cfitz/Cfitz.Tests.cs b/lib/filters/cfitz/tests/Cfitz.Tests.cs similarity index 100% rename from lib/filters/cfitz/Cfitz.Tests.cs rename to lib/filters/cfitz/tests/Cfitz.Tests.cs diff --git a/lib/filters/cfitz/Cfitz.Validation.Tests.cs b/lib/filters/cfitz/tests/Cfitz.Validation.Tests.cs similarity index 100% rename from lib/filters/cfitz/Cfitz.Validation.Tests.cs rename to lib/filters/cfitz/tests/Cfitz.Validation.Tests.cs diff --git a/lib/filters/cheby1/Cheby1.Quantower.Tests.cs b/lib/filters/cheby1/tests/Cheby1.Quantower.Tests.cs similarity index 100% rename from lib/filters/cheby1/Cheby1.Quantower.Tests.cs rename to lib/filters/cheby1/tests/Cheby1.Quantower.Tests.cs diff --git a/lib/filters/cheby1/Cheby1.Tests.cs b/lib/filters/cheby1/tests/Cheby1.Tests.cs similarity index 100% rename from lib/filters/cheby1/Cheby1.Tests.cs rename to lib/filters/cheby1/tests/Cheby1.Tests.cs diff --git a/lib/filters/cheby1/Cheby1.Validation.Tests.cs b/lib/filters/cheby1/tests/Cheby1.Validation.Tests.cs similarity index 100% rename from lib/filters/cheby1/Cheby1.Validation.Tests.cs rename to lib/filters/cheby1/tests/Cheby1.Validation.Tests.cs diff --git a/lib/filters/cheby2/Cheby2.Quantower.Tests.cs b/lib/filters/cheby2/tests/Cheby2.Quantower.Tests.cs similarity index 100% rename from lib/filters/cheby2/Cheby2.Quantower.Tests.cs rename to lib/filters/cheby2/tests/Cheby2.Quantower.Tests.cs diff --git a/lib/filters/cheby2/Cheby2.Tests.cs b/lib/filters/cheby2/tests/Cheby2.Tests.cs similarity index 100% rename from lib/filters/cheby2/Cheby2.Tests.cs rename to lib/filters/cheby2/tests/Cheby2.Tests.cs diff --git a/lib/filters/cheby2/Cheby2.Validation.Tests.cs b/lib/filters/cheby2/tests/Cheby2.Validation.Tests.cs similarity index 100% rename from lib/filters/cheby2/Cheby2.Validation.Tests.cs rename to lib/filters/cheby2/tests/Cheby2.Validation.Tests.cs diff --git a/lib/filters/edcf/Edcf.Quantower.Tests.cs b/lib/filters/edcf/tests/Edcf.Quantower.Tests.cs similarity index 100% rename from lib/filters/edcf/Edcf.Quantower.Tests.cs rename to lib/filters/edcf/tests/Edcf.Quantower.Tests.cs diff --git a/lib/filters/edcf/Edcf.Tests.cs b/lib/filters/edcf/tests/Edcf.Tests.cs similarity index 100% rename from lib/filters/edcf/Edcf.Tests.cs rename to lib/filters/edcf/tests/Edcf.Tests.cs diff --git a/lib/filters/edcf/Edcf.Validation.Tests.cs b/lib/filters/edcf/tests/Edcf.Validation.Tests.cs similarity index 100% rename from lib/filters/edcf/Edcf.Validation.Tests.cs rename to lib/filters/edcf/tests/Edcf.Validation.Tests.cs diff --git a/lib/filters/elliptic/Elliptic.Quantower.Tests.cs b/lib/filters/elliptic/tests/Elliptic.Quantower.Tests.cs similarity index 100% rename from lib/filters/elliptic/Elliptic.Quantower.Tests.cs rename to lib/filters/elliptic/tests/Elliptic.Quantower.Tests.cs diff --git a/lib/filters/elliptic/Elliptic.Tests.cs b/lib/filters/elliptic/tests/Elliptic.Tests.cs similarity index 100% rename from lib/filters/elliptic/Elliptic.Tests.cs rename to lib/filters/elliptic/tests/Elliptic.Tests.cs diff --git a/lib/filters/elliptic/Elliptic.Validation.Tests.cs b/lib/filters/elliptic/tests/Elliptic.Validation.Tests.cs similarity index 100% rename from lib/filters/elliptic/Elliptic.Validation.Tests.cs rename to lib/filters/elliptic/tests/Elliptic.Validation.Tests.cs diff --git a/lib/filters/gauss/Gauss.Quantower.Tests.cs b/lib/filters/gauss/tests/Gauss.Quantower.Tests.cs similarity index 100% rename from lib/filters/gauss/Gauss.Quantower.Tests.cs rename to lib/filters/gauss/tests/Gauss.Quantower.Tests.cs diff --git a/lib/filters/gauss/Gauss.Tests.cs b/lib/filters/gauss/tests/Gauss.Tests.cs similarity index 100% rename from lib/filters/gauss/Gauss.Tests.cs rename to lib/filters/gauss/tests/Gauss.Tests.cs diff --git a/lib/filters/gauss/Gauss.Validation.Tests.cs b/lib/filters/gauss/tests/Gauss.Validation.Tests.cs similarity index 100% rename from lib/filters/gauss/Gauss.Validation.Tests.cs rename to lib/filters/gauss/tests/Gauss.Validation.Tests.cs diff --git a/lib/filters/hann/Hann.Quantower.Tests.cs b/lib/filters/hann/tests/Hann.Quantower.Tests.cs similarity index 100% rename from lib/filters/hann/Hann.Quantower.Tests.cs rename to lib/filters/hann/tests/Hann.Quantower.Tests.cs diff --git a/lib/filters/hann/Hann.Tests.cs b/lib/filters/hann/tests/Hann.Tests.cs similarity index 100% rename from lib/filters/hann/Hann.Tests.cs rename to lib/filters/hann/tests/Hann.Tests.cs diff --git a/lib/filters/hann/Hann.Validation.Tests.cs b/lib/filters/hann/tests/Hann.Validation.Tests.cs similarity index 100% rename from lib/filters/hann/Hann.Validation.Tests.cs rename to lib/filters/hann/tests/Hann.Validation.Tests.cs diff --git a/lib/filters/hp/Hp.Quantower.Tests.cs b/lib/filters/hp/tests/Hp.Quantower.Tests.cs similarity index 100% rename from lib/filters/hp/Hp.Quantower.Tests.cs rename to lib/filters/hp/tests/Hp.Quantower.Tests.cs diff --git a/lib/filters/hp/Hp.Tests.cs b/lib/filters/hp/tests/Hp.Tests.cs similarity index 100% rename from lib/filters/hp/Hp.Tests.cs rename to lib/filters/hp/tests/Hp.Tests.cs diff --git a/lib/filters/hp/Hp.Validation.Tests.cs b/lib/filters/hp/tests/Hp.Validation.Tests.cs similarity index 100% rename from lib/filters/hp/Hp.Validation.Tests.cs rename to lib/filters/hp/tests/Hp.Validation.Tests.cs diff --git a/lib/filters/hpf/Hpf.Quantower.Tests.cs b/lib/filters/hpf/tests/Hpf.Quantower.Tests.cs similarity index 100% rename from lib/filters/hpf/Hpf.Quantower.Tests.cs rename to lib/filters/hpf/tests/Hpf.Quantower.Tests.cs diff --git a/lib/filters/hpf/Hpf.Tests.cs b/lib/filters/hpf/tests/Hpf.Tests.cs similarity index 100% rename from lib/filters/hpf/Hpf.Tests.cs rename to lib/filters/hpf/tests/Hpf.Tests.cs diff --git a/lib/filters/hpf/Hpf.Validation.Tests.cs b/lib/filters/hpf/tests/Hpf.Validation.Tests.cs similarity index 100% rename from lib/filters/hpf/Hpf.Validation.Tests.cs rename to lib/filters/hpf/tests/Hpf.Validation.Tests.cs diff --git a/lib/filters/kalman/Kalman.Quantower.Tests.cs b/lib/filters/kalman/tests/Kalman.Quantower.Tests.cs similarity index 100% rename from lib/filters/kalman/Kalman.Quantower.Tests.cs rename to lib/filters/kalman/tests/Kalman.Quantower.Tests.cs diff --git a/lib/filters/kalman/Kalman.Tests.cs b/lib/filters/kalman/tests/Kalman.Tests.cs similarity index 100% rename from lib/filters/kalman/Kalman.Tests.cs rename to lib/filters/kalman/tests/Kalman.Tests.cs diff --git a/lib/filters/kalman/Kalman.Validation.Tests.cs b/lib/filters/kalman/tests/Kalman.Validation.Tests.cs similarity index 100% rename from lib/filters/kalman/Kalman.Validation.Tests.cs rename to lib/filters/kalman/tests/Kalman.Validation.Tests.cs diff --git a/lib/filters/laguerre/Laguerre.Quantower.Tests.cs b/lib/filters/laguerre/tests/Laguerre.Quantower.Tests.cs similarity index 100% rename from lib/filters/laguerre/Laguerre.Quantower.Tests.cs rename to lib/filters/laguerre/tests/Laguerre.Quantower.Tests.cs diff --git a/lib/filters/laguerre/Laguerre.Tests.cs b/lib/filters/laguerre/tests/Laguerre.Tests.cs similarity index 100% rename from lib/filters/laguerre/Laguerre.Tests.cs rename to lib/filters/laguerre/tests/Laguerre.Tests.cs diff --git a/lib/filters/laguerre/Laguerre.Validation.Tests.cs b/lib/filters/laguerre/tests/Laguerre.Validation.Tests.cs similarity index 100% rename from lib/filters/laguerre/Laguerre.Validation.Tests.cs rename to lib/filters/laguerre/tests/Laguerre.Validation.Tests.cs diff --git a/lib/filters/lms/Lms.Quantower.Tests.cs b/lib/filters/lms/tests/Lms.Quantower.Tests.cs similarity index 100% rename from lib/filters/lms/Lms.Quantower.Tests.cs rename to lib/filters/lms/tests/Lms.Quantower.Tests.cs diff --git a/lib/filters/lms/Lms.Tests.cs b/lib/filters/lms/tests/Lms.Tests.cs similarity index 100% rename from lib/filters/lms/Lms.Tests.cs rename to lib/filters/lms/tests/Lms.Tests.cs diff --git a/lib/filters/lms/Lms.Validation.Tests.cs b/lib/filters/lms/tests/Lms.Validation.Tests.cs similarity index 100% rename from lib/filters/lms/Lms.Validation.Tests.cs rename to lib/filters/lms/tests/Lms.Validation.Tests.cs diff --git a/lib/filters/loess/Loess.Quantower.Tests.cs b/lib/filters/loess/tests/Loess.Quantower.Tests.cs similarity index 100% rename from lib/filters/loess/Loess.Quantower.Tests.cs rename to lib/filters/loess/tests/Loess.Quantower.Tests.cs diff --git a/lib/filters/loess/Loess.Tests.cs b/lib/filters/loess/tests/Loess.Tests.cs similarity index 100% rename from lib/filters/loess/Loess.Tests.cs rename to lib/filters/loess/tests/Loess.Tests.cs diff --git a/lib/filters/loess/Loess.Validation.Tests.cs b/lib/filters/loess/tests/Loess.Validation.Tests.cs similarity index 100% rename from lib/filters/loess/Loess.Validation.Tests.cs rename to lib/filters/loess/tests/Loess.Validation.Tests.cs diff --git a/lib/filters/modf/Modf.Quantower.Tests.cs b/lib/filters/modf/tests/Modf.Quantower.Tests.cs similarity index 100% rename from lib/filters/modf/Modf.Quantower.Tests.cs rename to lib/filters/modf/tests/Modf.Quantower.Tests.cs diff --git a/lib/filters/modf/Modf.Tests.cs b/lib/filters/modf/tests/Modf.Tests.cs similarity index 100% rename from lib/filters/modf/Modf.Tests.cs rename to lib/filters/modf/tests/Modf.Tests.cs diff --git a/lib/filters/modf/Modf.Validation.Tests.cs b/lib/filters/modf/tests/Modf.Validation.Tests.cs similarity index 100% rename from lib/filters/modf/Modf.Validation.Tests.cs rename to lib/filters/modf/tests/Modf.Validation.Tests.cs diff --git a/lib/filters/notch/Notch.Quantower.Tests.cs b/lib/filters/notch/tests/Notch.Quantower.Tests.cs similarity index 100% rename from lib/filters/notch/Notch.Quantower.Tests.cs rename to lib/filters/notch/tests/Notch.Quantower.Tests.cs diff --git a/lib/filters/notch/Notch.Tests.cs b/lib/filters/notch/tests/Notch.Tests.cs similarity index 100% rename from lib/filters/notch/Notch.Tests.cs rename to lib/filters/notch/tests/Notch.Tests.cs diff --git a/lib/filters/notch/Notch.Validation.Tests.cs b/lib/filters/notch/tests/Notch.Validation.Tests.cs similarity index 100% rename from lib/filters/notch/Notch.Validation.Tests.cs rename to lib/filters/notch/tests/Notch.Validation.Tests.cs diff --git a/lib/filters/nw/Nw.Quantower.Tests.cs b/lib/filters/nw/tests/Nw.Quantower.Tests.cs similarity index 100% rename from lib/filters/nw/Nw.Quantower.Tests.cs rename to lib/filters/nw/tests/Nw.Quantower.Tests.cs diff --git a/lib/filters/nw/Nw.Tests.cs b/lib/filters/nw/tests/Nw.Tests.cs similarity index 100% rename from lib/filters/nw/Nw.Tests.cs rename to lib/filters/nw/tests/Nw.Tests.cs diff --git a/lib/filters/nw/Nw.Validation.Tests.cs b/lib/filters/nw/tests/Nw.Validation.Tests.cs similarity index 100% rename from lib/filters/nw/Nw.Validation.Tests.cs rename to lib/filters/nw/tests/Nw.Validation.Tests.cs diff --git a/lib/filters/oneeuro/OneEuro.Quantower.Tests.cs b/lib/filters/oneeuro/tests/OneEuro.Quantower.Tests.cs similarity index 100% rename from lib/filters/oneeuro/OneEuro.Quantower.Tests.cs rename to lib/filters/oneeuro/tests/OneEuro.Quantower.Tests.cs diff --git a/lib/filters/oneeuro/OneEuro.Tests.cs b/lib/filters/oneeuro/tests/OneEuro.Tests.cs similarity index 100% rename from lib/filters/oneeuro/OneEuro.Tests.cs rename to lib/filters/oneeuro/tests/OneEuro.Tests.cs diff --git a/lib/filters/oneeuro/OneEuro.Validation.Tests.cs b/lib/filters/oneeuro/tests/OneEuro.Validation.Tests.cs similarity index 100% rename from lib/filters/oneeuro/OneEuro.Validation.Tests.cs rename to lib/filters/oneeuro/tests/OneEuro.Validation.Tests.cs diff --git a/lib/filters/rls/Rls.Quantower.Tests.cs b/lib/filters/rls/tests/Rls.Quantower.Tests.cs similarity index 100% rename from lib/filters/rls/Rls.Quantower.Tests.cs rename to lib/filters/rls/tests/Rls.Quantower.Tests.cs diff --git a/lib/filters/rls/Rls.Tests.cs b/lib/filters/rls/tests/Rls.Tests.cs similarity index 100% rename from lib/filters/rls/Rls.Tests.cs rename to lib/filters/rls/tests/Rls.Tests.cs diff --git a/lib/filters/rls/Rls.Validation.Tests.cs b/lib/filters/rls/tests/Rls.Validation.Tests.cs similarity index 100% rename from lib/filters/rls/Rls.Validation.Tests.cs rename to lib/filters/rls/tests/Rls.Validation.Tests.cs diff --git a/lib/filters/rmed/Rmed.Quantower.Tests.cs b/lib/filters/rmed/tests/Rmed.Quantower.Tests.cs similarity index 100% rename from lib/filters/rmed/Rmed.Quantower.Tests.cs rename to lib/filters/rmed/tests/Rmed.Quantower.Tests.cs diff --git a/lib/filters/rmed/Rmed.Tests.cs b/lib/filters/rmed/tests/Rmed.Tests.cs similarity index 100% rename from lib/filters/rmed/Rmed.Tests.cs rename to lib/filters/rmed/tests/Rmed.Tests.cs diff --git a/lib/filters/rmed/Rmed.Validation.Tests.cs b/lib/filters/rmed/tests/Rmed.Validation.Tests.cs similarity index 100% rename from lib/filters/rmed/Rmed.Validation.Tests.cs rename to lib/filters/rmed/tests/Rmed.Validation.Tests.cs diff --git a/lib/filters/roofing/Roofing.Quantower.Tests.cs b/lib/filters/roofing/tests/Roofing.Quantower.Tests.cs similarity index 100% rename from lib/filters/roofing/Roofing.Quantower.Tests.cs rename to lib/filters/roofing/tests/Roofing.Quantower.Tests.cs diff --git a/lib/filters/roofing/Roofing.Tests.cs b/lib/filters/roofing/tests/Roofing.Tests.cs similarity index 100% rename from lib/filters/roofing/Roofing.Tests.cs rename to lib/filters/roofing/tests/Roofing.Tests.cs diff --git a/lib/filters/roofing/Roofing.Validation.Tests.cs b/lib/filters/roofing/tests/Roofing.Validation.Tests.cs similarity index 100% rename from lib/filters/roofing/Roofing.Validation.Tests.cs rename to lib/filters/roofing/tests/Roofing.Validation.Tests.cs diff --git a/lib/filters/sak/Sak.Quantower.Tests.cs b/lib/filters/sak/tests/Sak.Quantower.Tests.cs similarity index 100% rename from lib/filters/sak/Sak.Quantower.Tests.cs rename to lib/filters/sak/tests/Sak.Quantower.Tests.cs diff --git a/lib/filters/sak/Sak.Tests.cs b/lib/filters/sak/tests/Sak.Tests.cs similarity index 100% rename from lib/filters/sak/Sak.Tests.cs rename to lib/filters/sak/tests/Sak.Tests.cs diff --git a/lib/filters/sak/Sak.Validation.Tests.cs b/lib/filters/sak/tests/Sak.Validation.Tests.cs similarity index 100% rename from lib/filters/sak/Sak.Validation.Tests.cs rename to lib/filters/sak/tests/Sak.Validation.Tests.cs diff --git a/lib/filters/sgf/Sgf.Quantower.Tests.cs b/lib/filters/sgf/tests/Sgf.Quantower.Tests.cs similarity index 100% rename from lib/filters/sgf/Sgf.Quantower.Tests.cs rename to lib/filters/sgf/tests/Sgf.Quantower.Tests.cs diff --git a/lib/filters/sgf/Sgf.Tests.cs b/lib/filters/sgf/tests/Sgf.Tests.cs similarity index 100% rename from lib/filters/sgf/Sgf.Tests.cs rename to lib/filters/sgf/tests/Sgf.Tests.cs diff --git a/lib/filters/sgf/Sgf.Validation.Tests.cs b/lib/filters/sgf/tests/Sgf.Validation.Tests.cs similarity index 100% rename from lib/filters/sgf/Sgf.Validation.Tests.cs rename to lib/filters/sgf/tests/Sgf.Validation.Tests.cs diff --git a/lib/filters/spbf/Spbf.Quantower.Tests.cs b/lib/filters/spbf/tests/Spbf.Quantower.Tests.cs similarity index 100% rename from lib/filters/spbf/Spbf.Quantower.Tests.cs rename to lib/filters/spbf/tests/Spbf.Quantower.Tests.cs diff --git a/lib/filters/spbf/Spbf.Tests.cs b/lib/filters/spbf/tests/Spbf.Tests.cs similarity index 100% rename from lib/filters/spbf/Spbf.Tests.cs rename to lib/filters/spbf/tests/Spbf.Tests.cs diff --git a/lib/filters/spbf/Spbf.Validation.Tests.cs b/lib/filters/spbf/tests/Spbf.Validation.Tests.cs similarity index 100% rename from lib/filters/spbf/Spbf.Validation.Tests.cs rename to lib/filters/spbf/tests/Spbf.Validation.Tests.cs diff --git a/lib/filters/ssf2/Ssf2.Quantower.Tests.cs b/lib/filters/ssf2/tests/Ssf2.Quantower.Tests.cs similarity index 100% rename from lib/filters/ssf2/Ssf2.Quantower.Tests.cs rename to lib/filters/ssf2/tests/Ssf2.Quantower.Tests.cs diff --git a/lib/filters/ssf2/Ssf2.Tests.cs b/lib/filters/ssf2/tests/Ssf2.Tests.cs similarity index 100% rename from lib/filters/ssf2/Ssf2.Tests.cs rename to lib/filters/ssf2/tests/Ssf2.Tests.cs diff --git a/lib/filters/ssf2/Ssf2.Validation.Tests.cs b/lib/filters/ssf2/tests/Ssf2.Validation.Tests.cs similarity index 100% rename from lib/filters/ssf2/Ssf2.Validation.Tests.cs rename to lib/filters/ssf2/tests/Ssf2.Validation.Tests.cs diff --git a/lib/filters/ssf3/Ssf3.Quantower.Tests.cs b/lib/filters/ssf3/tests/Ssf3.Quantower.Tests.cs similarity index 100% rename from lib/filters/ssf3/Ssf3.Quantower.Tests.cs rename to lib/filters/ssf3/tests/Ssf3.Quantower.Tests.cs diff --git a/lib/filters/ssf3/Ssf3.Tests.cs b/lib/filters/ssf3/tests/Ssf3.Tests.cs similarity index 100% rename from lib/filters/ssf3/Ssf3.Tests.cs rename to lib/filters/ssf3/tests/Ssf3.Tests.cs diff --git a/lib/filters/ssf3/Ssf3.Validation.Tests.cs b/lib/filters/ssf3/tests/Ssf3.Validation.Tests.cs similarity index 100% rename from lib/filters/ssf3/Ssf3.Validation.Tests.cs rename to lib/filters/ssf3/tests/Ssf3.Validation.Tests.cs diff --git a/lib/filters/usf/Usf.Quantower.Tests.cs b/lib/filters/usf/tests/Usf.Quantower.Tests.cs similarity index 100% rename from lib/filters/usf/Usf.Quantower.Tests.cs rename to lib/filters/usf/tests/Usf.Quantower.Tests.cs diff --git a/lib/filters/usf/Usf.Tests.cs b/lib/filters/usf/tests/Usf.Tests.cs similarity index 100% rename from lib/filters/usf/Usf.Tests.cs rename to lib/filters/usf/tests/Usf.Tests.cs diff --git a/lib/filters/usf/Usf.Validation.Tests.cs b/lib/filters/usf/tests/Usf.Validation.Tests.cs similarity index 100% rename from lib/filters/usf/Usf.Validation.Tests.cs rename to lib/filters/usf/tests/Usf.Validation.Tests.cs diff --git a/lib/filters/voss/Voss.Quantower.Tests.cs b/lib/filters/voss/tests/Voss.Quantower.Tests.cs similarity index 100% rename from lib/filters/voss/Voss.Quantower.Tests.cs rename to lib/filters/voss/tests/Voss.Quantower.Tests.cs diff --git a/lib/filters/voss/Voss.Tests.cs b/lib/filters/voss/tests/Voss.Tests.cs similarity index 100% rename from lib/filters/voss/Voss.Tests.cs rename to lib/filters/voss/tests/Voss.Tests.cs diff --git a/lib/filters/voss/Voss.Validation.Tests.cs b/lib/filters/voss/tests/Voss.Validation.Tests.cs similarity index 100% rename from lib/filters/voss/Voss.Validation.Tests.cs rename to lib/filters/voss/tests/Voss.Validation.Tests.cs diff --git a/lib/filters/wavelet/Wavelet.Quantower.Tests.cs b/lib/filters/wavelet/tests/Wavelet.Quantower.Tests.cs similarity index 100% rename from lib/filters/wavelet/Wavelet.Quantower.Tests.cs rename to lib/filters/wavelet/tests/Wavelet.Quantower.Tests.cs diff --git a/lib/filters/wavelet/Wavelet.Tests.cs b/lib/filters/wavelet/tests/Wavelet.Tests.cs similarity index 100% rename from lib/filters/wavelet/Wavelet.Tests.cs rename to lib/filters/wavelet/tests/Wavelet.Tests.cs diff --git a/lib/filters/wavelet/Wavelet.Validation.Tests.cs b/lib/filters/wavelet/tests/Wavelet.Validation.Tests.cs similarity index 100% rename from lib/filters/wavelet/Wavelet.Validation.Tests.cs rename to lib/filters/wavelet/tests/Wavelet.Validation.Tests.cs diff --git a/lib/filters/wiener/Wiener.Quantower.Tests.cs b/lib/filters/wiener/tests/Wiener.Quantower.Tests.cs similarity index 100% rename from lib/filters/wiener/Wiener.Quantower.Tests.cs rename to lib/filters/wiener/tests/Wiener.Quantower.Tests.cs diff --git a/lib/filters/wiener/Wiener.Tests.cs b/lib/filters/wiener/tests/Wiener.Tests.cs similarity index 100% rename from lib/filters/wiener/Wiener.Tests.cs rename to lib/filters/wiener/tests/Wiener.Tests.cs diff --git a/lib/filters/wiener/Wiener.Validation.Tests.cs b/lib/filters/wiener/tests/Wiener.Validation.Tests.cs similarity index 100% rename from lib/filters/wiener/Wiener.Validation.Tests.cs rename to lib/filters/wiener/tests/Wiener.Validation.Tests.cs diff --git a/lib/forecasts/afirma/Afirma.Quantower.Tests.cs b/lib/forecasts/afirma/tests/Afirma.Quantower.Tests.cs similarity index 100% rename from lib/forecasts/afirma/Afirma.Quantower.Tests.cs rename to lib/forecasts/afirma/tests/Afirma.Quantower.Tests.cs diff --git a/lib/forecasts/afirma/Afirma.Tests.cs b/lib/forecasts/afirma/tests/Afirma.Tests.cs similarity index 100% rename from lib/forecasts/afirma/Afirma.Tests.cs rename to lib/forecasts/afirma/tests/Afirma.Tests.cs diff --git a/lib/forecasts/afirma/Afirma.Validation.Tests.cs b/lib/forecasts/afirma/tests/Afirma.Validation.Tests.cs similarity index 100% rename from lib/forecasts/afirma/Afirma.Validation.Tests.cs rename to lib/forecasts/afirma/tests/Afirma.Validation.Tests.cs diff --git a/lib/momentum/asi/Asi.Quantower.Tests.cs b/lib/momentum/asi/tests/Asi.Quantower.Tests.cs similarity index 100% rename from lib/momentum/asi/Asi.Quantower.Tests.cs rename to lib/momentum/asi/tests/Asi.Quantower.Tests.cs diff --git a/lib/momentum/asi/Asi.Tests.cs b/lib/momentum/asi/tests/Asi.Tests.cs similarity index 100% rename from lib/momentum/asi/Asi.Tests.cs rename to lib/momentum/asi/tests/Asi.Tests.cs diff --git a/lib/momentum/asi/Asi.Validation.Tests.cs b/lib/momentum/asi/tests/Asi.Validation.Tests.cs similarity index 100% rename from lib/momentum/asi/Asi.Validation.Tests.cs rename to lib/momentum/asi/tests/Asi.Validation.Tests.cs diff --git a/lib/momentum/bias/Bias.Quantower.Tests.cs b/lib/momentum/bias/tests/Bias.Quantower.Tests.cs similarity index 100% rename from lib/momentum/bias/Bias.Quantower.Tests.cs rename to lib/momentum/bias/tests/Bias.Quantower.Tests.cs diff --git a/lib/momentum/bias/Bias.Tests.cs b/lib/momentum/bias/tests/Bias.Tests.cs similarity index 100% rename from lib/momentum/bias/Bias.Tests.cs rename to lib/momentum/bias/tests/Bias.Tests.cs diff --git a/lib/momentum/bias/Bias.Validation.Tests.cs b/lib/momentum/bias/tests/Bias.Validation.Tests.cs similarity index 100% rename from lib/momentum/bias/Bias.Validation.Tests.cs rename to lib/momentum/bias/tests/Bias.Validation.Tests.cs diff --git a/lib/momentum/bop/Bop.md b/lib/momentum/bop/Bop.md index fd36141a..bc8a5c3c 100644 --- a/lib/momentum/bop/Bop.md +++ b/lib/momentum/bop/Bop.md @@ -286,65 +286,6 @@ foreach (var bar in liveStream) } ``` -## C# Implementation Considerations - -### Stateless Design - -```csharp -public TValue Last { get; private set; } -public static bool IsHot => true; -public static int WarmupPeriod => 0; -``` - -BOP requires no warmup: IsHot is always true, WarmupPeriod is always zero. The only state is `Last`, which holds the most recent output for event subscribers. - -### SIMD Vectorization - -```csharp -if (Vector.IsHardwareAccelerated && len >= Vector.Count) -{ - var epsilon = new Vector(double.Epsilon); - // ... - var range = h - l; - var body = c - o; - var mask = Vector.GreaterThan(range, epsilon); - var div = body / range; - var result = Vector.ConditionalSelect(mask, div, Vector.Zero); -} -``` - -Uses `System.Numerics.Vector` for portable SIMD. `Vector.ConditionalSelect` handles zero-range case without branching. Hardware detection via `Vector.IsHardwareAccelerated`. - -### TValue vs TBar Input - -```csharp -public TValue Update(TBar input, bool isNew = true) -{ - double range = input.High - input.Low; - double bop = range > double.Epsilon ? (input.Close - input.Open) / range : 0; - // ... -} - -public TValue Update(TValue input, bool isNew = true) -{ - // Cannot calculate BOP from single value - Last = new TValue(input.Time, 0); - return Last; -} -``` - -The TValue overload exists for interface compliance but produces zero output. BOP fundamentally requires OHLC data. - -### Memory Layout - -| Component | Size | Lifetime | -| :-------- | ---: | :------- | -| Bop instance | ~24 bytes | Indicator lifetime | -| Last (TValue) | 16 bytes | Per update | -| **Total** | **~24 bytes** | **Fixed** | - -Zero per-bar allocations. No state accumulation. Memory footprint independent of data volume. - ## References - Livshin, I. (2001). "Balance of Power." *Technical Analysis of Stocks & Commodities*, August 2001. diff --git a/lib/momentum/bop/Bop.Quantower.Tests.cs b/lib/momentum/bop/tests/Bop.Quantower.Tests.cs similarity index 100% rename from lib/momentum/bop/Bop.Quantower.Tests.cs rename to lib/momentum/bop/tests/Bop.Quantower.Tests.cs diff --git a/lib/momentum/bop/Bop.Tests.cs b/lib/momentum/bop/tests/Bop.Tests.cs similarity index 100% rename from lib/momentum/bop/Bop.Tests.cs rename to lib/momentum/bop/tests/Bop.Tests.cs diff --git a/lib/momentum/bop/Bop.Validation.Tests.cs b/lib/momentum/bop/tests/Bop.Validation.Tests.cs similarity index 100% rename from lib/momentum/bop/Bop.Validation.Tests.cs rename to lib/momentum/bop/tests/Bop.Validation.Tests.cs diff --git a/lib/momentum/cci/Cci.Quantower.Tests.cs b/lib/momentum/cci/tests/Cci.Quantower.Tests.cs similarity index 100% rename from lib/momentum/cci/Cci.Quantower.Tests.cs rename to lib/momentum/cci/tests/Cci.Quantower.Tests.cs diff --git a/lib/momentum/cci/Cci.Tests.cs b/lib/momentum/cci/tests/Cci.Tests.cs similarity index 100% rename from lib/momentum/cci/Cci.Tests.cs rename to lib/momentum/cci/tests/Cci.Tests.cs diff --git a/lib/momentum/cci/Cci.Validation.Tests.cs b/lib/momentum/cci/tests/Cci.Validation.Tests.cs similarity index 100% rename from lib/momentum/cci/Cci.Validation.Tests.cs rename to lib/momentum/cci/tests/Cci.Validation.Tests.cs diff --git a/lib/momentum/cfb/Cfb.md b/lib/momentum/cfb/Cfb.md index 096ba20a..c71519f7 100644 --- a/lib/momentum/cfb/Cfb.md +++ b/lib/momentum/cfb/Cfb.md @@ -303,66 +303,6 @@ var cfb = new Cfb(customLengths); // Faster computation, coarser granularity ``` -## C# Implementation Considerations - -### Running Sum State Management - -```csharp -private readonly double[] _runningSums; -private readonly double[] _p_runningSums; - -if (isNew) -{ - Array.Copy(_runningSums, _p_runningSums, _lengths.Length); -} -else -{ - Array.Copy(_p_runningSums, _runningSums, _lengths.Length); -} -``` - -Bar correction requires copying 96 running sums. Array.Copy is optimized for this pattern but still ~768 bytes per correction. - -### Ring Buffer Architecture - -```csharp -private readonly RingBuffer _prices; -private readonly RingBuffer _volatility; -``` - -Two ring buffers of size 194 (maxLength + 1). Prices enable net-move calculation; volatility enables running-sum updates. Ring buffers provide O(1) indexed access to historical values. - -### Batch Mode Optimization - -```csharp -Span vol = len <= StackallocThreshold - ? stackalloc double[len] - : new double[len]; -``` - -Batch mode pre-calculates all volatility values, then scans with running sums. For short series (≤256 bars), uses stackalloc to avoid heap allocation. - -### State Record Structure - -```csharp -[StructLayout(LayoutKind.Auto)] -private record struct State(double PrevCfb, double LastPrice, double LastValidValue); -``` - -Compact state record holds previous CFB (for decay), last price (for volatility calculation), and last valid value (for NaN handling). LayoutKind.Auto allows runtime optimization. - -### Memory Layout Summary - -| Component | Allocation | Lifetime | -| :-------- | ---------: | :------- | -| Length array | 384 bytes | Instance lifetime | -| Running sums (2×) | 1,536 bytes | Instance lifetime | -| Price buffer | 1,552 bytes | Instance lifetime | -| Volatility buffer | 1,552 bytes | Instance lifetime | -| State records (2×) | 48 bytes | Instance lifetime | -| Batch temp arrays | Variable | Per batch call | -| **Total fixed** | **~5 KB** | **Per instance** | - ## References - Jurik Research. "Composite Fractal Behavior." http://jurikres.com/ diff --git a/lib/momentum/cfb/Cfb.Quantower.Tests.cs b/lib/momentum/cfb/tests/Cfb.Quantower.Tests.cs similarity index 100% rename from lib/momentum/cfb/Cfb.Quantower.Tests.cs rename to lib/momentum/cfb/tests/Cfb.Quantower.Tests.cs diff --git a/lib/momentum/cfb/Cfb.Tests.cs b/lib/momentum/cfb/tests/Cfb.Tests.cs similarity index 100% rename from lib/momentum/cfb/Cfb.Tests.cs rename to lib/momentum/cfb/tests/Cfb.Tests.cs diff --git a/lib/momentum/cfb/Cfb.Validation.Tests.cs b/lib/momentum/cfb/tests/Cfb.Validation.Tests.cs similarity index 100% rename from lib/momentum/cfb/Cfb.Validation.Tests.cs rename to lib/momentum/cfb/tests/Cfb.Validation.Tests.cs diff --git a/lib/momentum/cmo/Cmo.Quantower.Tests.cs b/lib/momentum/cmo/tests/Cmo.Quantower.Tests.cs similarity index 100% rename from lib/momentum/cmo/Cmo.Quantower.Tests.cs rename to lib/momentum/cmo/tests/Cmo.Quantower.Tests.cs diff --git a/lib/momentum/cmo/Cmo.Tests.cs b/lib/momentum/cmo/tests/Cmo.Tests.cs similarity index 100% rename from lib/momentum/cmo/Cmo.Tests.cs rename to lib/momentum/cmo/tests/Cmo.Tests.cs diff --git a/lib/momentum/cmo/Cmo.Validation.Tests.cs b/lib/momentum/cmo/tests/Cmo.Validation.Tests.cs similarity index 100% rename from lib/momentum/cmo/Cmo.Validation.Tests.cs rename to lib/momentum/cmo/tests/Cmo.Validation.Tests.cs diff --git a/lib/momentum/macd/Macd.md b/lib/momentum/macd/Macd.md index 6edf8618..4cf1f068 100644 --- a/lib/momentum/macd/Macd.md +++ b/lib/momentum/macd/Macd.md @@ -311,75 +311,6 @@ macd.Pub += (sender, args) => source.Add(new TValue(DateTime.UtcNow, 100.0)); ``` -## C# Implementation Considerations - -### Triple EMA Architecture - -```csharp -private readonly Ema _fastEma; -private readonly Ema _slowEma; -private readonly Ema _signalEma; -``` - -MACD delegates all state management to internal EMA instances. No separate state record needed: the three EMAs encapsulate all required history. Reset propagates to all three. - -### Composite State Management - -The `isNew` parameter cascades through all three EMAs: - -```csharp -var fast = _fastEma.Update(input, isNew); -var slow = _slowEma.Update(input, isNew); -// ... -var signal = _signalEma.Update(macdTValue, isNew); -``` - -When `isNew=false`, all three EMAs roll back to previous state before reprocessing. This ensures bar corrections work correctly across the entire calculation chain. - -### Multi-Output Pattern - -MACD produces three outputs from single input: - -```csharp -public TValue Last { get; private set; } // MACD line -public TValue Signal { get; private set; } // Signal line -public TValue Histogram { get; private set; } // Histogram -``` - -The `Pub` event publishes only the MACD line value. Consumers requiring signal or histogram must access properties directly or subscribe to a wrapper. - -### ArrayPool for Span Calculate - -```csharp -double[] fastBuffer = ArrayPool.Shared.Rent(len); -double[] slowBuffer = ArrayPool.Shared.Rent(len); -try -{ - // Use buffers - SimdExtensions.Subtract(fastSpan, slowSpan, destination); -} -finally -{ - ArrayPool.Shared.Return(fastBuffer); - ArrayPool.Shared.Return(slowBuffer); -} -``` - -Span-based Calculate rents temporary buffers for intermediate EMA results. Total temporary allocation: 2× input length. ArrayPool eliminates GC pressure during repeated calls. - -### Memory Layout Summary - -| Component | Size | Lifetime | -| :-------- | ---: | :------- | -| Macd instance | ~200 bytes | Indicator lifetime | -| Fast EMA state | ~40 bytes | Per EMA | -| Slow EMA state | ~40 bytes | Per EMA | -| Signal EMA state | ~40 bytes | Per EMA | -| ArrayPool buffers | 2×N×8 bytes | Per batch call | -| **Streaming overhead** | **~320 bytes** | **Fixed** | - -Zero allocations in streaming hot path. Batch mode uses ArrayPool, returning memory after each call. - ## References - Appel, G. (1979). "The Moving Average Convergence Divergence Trading Method." Signalert Corporation. diff --git a/lib/momentum/macd/Macd.Quantower.Tests.cs b/lib/momentum/macd/tests/Macd.Quantower.Tests.cs similarity index 100% rename from lib/momentum/macd/Macd.Quantower.Tests.cs rename to lib/momentum/macd/tests/Macd.Quantower.Tests.cs diff --git a/lib/momentum/macd/Macd.Tests.cs b/lib/momentum/macd/tests/Macd.Tests.cs similarity index 100% rename from lib/momentum/macd/Macd.Tests.cs rename to lib/momentum/macd/tests/Macd.Tests.cs diff --git a/lib/momentum/macd/Macd.Validation.Tests.cs b/lib/momentum/macd/tests/Macd.Validation.Tests.cs similarity index 100% rename from lib/momentum/macd/Macd.Validation.Tests.cs rename to lib/momentum/macd/tests/Macd.Validation.Tests.cs diff --git a/lib/momentum/mom/Mom.Quantower.Tests.cs b/lib/momentum/mom/tests/Mom.Quantower.Tests.cs similarity index 100% rename from lib/momentum/mom/Mom.Quantower.Tests.cs rename to lib/momentum/mom/tests/Mom.Quantower.Tests.cs diff --git a/lib/momentum/mom/Mom.Tests.cs b/lib/momentum/mom/tests/Mom.Tests.cs similarity index 100% rename from lib/momentum/mom/Mom.Tests.cs rename to lib/momentum/mom/tests/Mom.Tests.cs diff --git a/lib/momentum/mom/Mom.Validation.Tests.cs b/lib/momentum/mom/tests/Mom.Validation.Tests.cs similarity index 100% rename from lib/momentum/mom/Mom.Validation.Tests.cs rename to lib/momentum/mom/tests/Mom.Validation.Tests.cs diff --git a/lib/momentum/pmo/Pmo.Quantower.Tests.cs b/lib/momentum/pmo/tests/Pmo.Quantower.Tests.cs similarity index 100% rename from lib/momentum/pmo/Pmo.Quantower.Tests.cs rename to lib/momentum/pmo/tests/Pmo.Quantower.Tests.cs diff --git a/lib/momentum/pmo/Pmo.Tests.cs b/lib/momentum/pmo/tests/Pmo.Tests.cs similarity index 100% rename from lib/momentum/pmo/Pmo.Tests.cs rename to lib/momentum/pmo/tests/Pmo.Tests.cs diff --git a/lib/momentum/pmo/Pmo.Validation.Tests.cs b/lib/momentum/pmo/tests/Pmo.Validation.Tests.cs similarity index 100% rename from lib/momentum/pmo/Pmo.Validation.Tests.cs rename to lib/momentum/pmo/tests/Pmo.Validation.Tests.cs diff --git a/lib/momentum/ppo/Ppo.Quantower.Tests.cs b/lib/momentum/ppo/tests/Ppo.Quantower.Tests.cs similarity index 100% rename from lib/momentum/ppo/Ppo.Quantower.Tests.cs rename to lib/momentum/ppo/tests/Ppo.Quantower.Tests.cs diff --git a/lib/momentum/ppo/Ppo.Tests.cs b/lib/momentum/ppo/tests/Ppo.Tests.cs similarity index 100% rename from lib/momentum/ppo/Ppo.Tests.cs rename to lib/momentum/ppo/tests/Ppo.Tests.cs diff --git a/lib/momentum/ppo/Ppo.Validation.Tests.cs b/lib/momentum/ppo/tests/Ppo.Validation.Tests.cs similarity index 100% rename from lib/momentum/ppo/Ppo.Validation.Tests.cs rename to lib/momentum/ppo/tests/Ppo.Validation.Tests.cs diff --git a/lib/momentum/prs/Prs.Quantower.Tests.cs b/lib/momentum/prs/tests/Prs.Quantower.Tests.cs similarity index 100% rename from lib/momentum/prs/Prs.Quantower.Tests.cs rename to lib/momentum/prs/tests/Prs.Quantower.Tests.cs diff --git a/lib/momentum/prs/Prs.Tests.cs b/lib/momentum/prs/tests/Prs.Tests.cs similarity index 100% rename from lib/momentum/prs/Prs.Tests.cs rename to lib/momentum/prs/tests/Prs.Tests.cs diff --git a/lib/momentum/prs/Prs.Validation.Tests.cs b/lib/momentum/prs/tests/Prs.Validation.Tests.cs similarity index 100% rename from lib/momentum/prs/Prs.Validation.Tests.cs rename to lib/momentum/prs/tests/Prs.Validation.Tests.cs diff --git a/lib/momentum/roc/Roc.Quantower.Tests.cs b/lib/momentum/roc/tests/Roc.Quantower.Tests.cs similarity index 100% rename from lib/momentum/roc/Roc.Quantower.Tests.cs rename to lib/momentum/roc/tests/Roc.Quantower.Tests.cs diff --git a/lib/momentum/roc/Roc.Tests.cs b/lib/momentum/roc/tests/Roc.Tests.cs similarity index 100% rename from lib/momentum/roc/Roc.Tests.cs rename to lib/momentum/roc/tests/Roc.Tests.cs diff --git a/lib/momentum/roc/Roc.Validation.Tests.cs b/lib/momentum/roc/tests/Roc.Validation.Tests.cs similarity index 100% rename from lib/momentum/roc/Roc.Validation.Tests.cs rename to lib/momentum/roc/tests/Roc.Validation.Tests.cs diff --git a/lib/momentum/rocp/Rocp.Quantower.Tests.cs b/lib/momentum/rocp/Rocp.Quantower.Tests.cs deleted file mode 100644 index 8b5e5570..00000000 --- a/lib/momentum/rocp/Rocp.Quantower.Tests.cs +++ /dev/null @@ -1,62 +0,0 @@ -using TradingPlatform.BusinessLayer; -using Xunit; - -namespace QuanTAlib.Tests; - -public class RocpIndicatorTests -{ - [Fact] - public void Constructor_InitializesDefaults() - { - var indicator = new RocpIndicator(); - Assert.Equal(9, indicator.Period); - Assert.Equal(SourceType.Close, indicator.Source); - Assert.True(indicator.ShowColdValues); - Assert.Equal("ROCP - Rate of Change Percentage", indicator.Name); - Assert.Contains("100 × (current - past) / past", indicator.Description, StringComparison.Ordinal); - Assert.True(indicator.SeparateWindow); - Assert.False(indicator.OnBackGround); - } - - [Fact] - public void ShortName_ReflectsPeriod() - { - var indicator = new RocpIndicator { Period = 14 }; - Assert.Equal("ROCP(14)", indicator.ShortName); - } - - [Fact] - public void MinHistoryDepths_IsPeriodPlusOne() - { - var indicator = new RocpIndicator { Period = 9 }; - Assert.Equal(10, indicator.MinHistoryDepths); - } - - [Fact] - public void MinHistoryDepths_MatchesWatchlistInterface() - { - var indicator = new RocpIndicator { Period = 17 }; - Assert.Equal(18, ((IWatchlistIndicator)indicator).MinHistoryDepths); - } - - [Fact] - public void Period_CanBeSet() - { - var indicator = new RocpIndicator { Period = 20 }; - Assert.Equal(20, indicator.Period); - } - - [Fact] - public void Source_CanBeSet() - { - var indicator = new RocpIndicator { Source = SourceType.Open }; - Assert.Equal(SourceType.Open, indicator.Source); - } - - [Fact] - public void ShowColdValues_CanBeSet() - { - var indicator = new RocpIndicator { ShowColdValues = false }; - Assert.False(indicator.ShowColdValues); - } -} diff --git a/lib/momentum/rocp/tests/Rocp.Quantower.Tests.cs b/lib/momentum/rocp/tests/Rocp.Quantower.Tests.cs new file mode 100644 index 00000000..a5407add --- /dev/null +++ b/lib/momentum/rocp/tests/Rocp.Quantower.Tests.cs @@ -0,0 +1,265 @@ +using TradingPlatform.BusinessLayer; +using Xunit; + +namespace QuanTAlib.Tests; + +public class RocpIndicatorTests +{ + [Fact] + public void Constructor_InitializesDefaults() + { + var indicator = new RocpIndicator(); + Assert.Equal(9, indicator.Period); + Assert.Equal(SourceType.Close, indicator.Source); + Assert.True(indicator.ShowColdValues); + Assert.Equal("ROCP - Rate of Change Percentage", indicator.Name); + Assert.Contains("100 × (current - past) / past", indicator.Description, StringComparison.Ordinal); + Assert.True(indicator.SeparateWindow); + Assert.False(indicator.OnBackGround); + } + + [Fact] + public void ShortName_ReflectsPeriod() + { + var indicator = new RocpIndicator { Period = 14 }; + Assert.Equal("ROCP(14)", indicator.ShortName); + } + + [Fact] + public void MinHistoryDepths_IsPeriodPlusOne() + { + var indicator = new RocpIndicator { Period = 9 }; + Assert.Equal(10, indicator.MinHistoryDepths); + } + + [Fact] + public void MinHistoryDepths_MatchesWatchlistInterface() + { + var indicator = new RocpIndicator { Period = 17 }; + Assert.Equal(18, ((IWatchlistIndicator)indicator).MinHistoryDepths); + } + + [Fact] + public void Period_CanBeSet() + { + var indicator = new RocpIndicator { Period = 20 }; + Assert.Equal(20, indicator.Period); + } + + [Fact] + public void Source_CanBeSet() + { + var indicator = new RocpIndicator { Source = SourceType.Open }; + Assert.Equal(SourceType.Open, indicator.Source); + } + + [Fact] + public void ShowColdValues_CanBeSet() + { + var indicator = new RocpIndicator { ShowColdValues = false }; + Assert.False(indicator.ShowColdValues); + } + + [Fact] + public void Initialize_CreatesLineSeries() + { + var indicator = new RocpIndicator(); + indicator.Initialize(); + + Assert.Equal(2, indicator.LinesSeries.Count); + Assert.Equal("ROCP", indicator.LinesSeries[0].Name); + Assert.Equal("Zero", indicator.LinesSeries[1].Name); + } + + [Fact] + public void ProcessUpdate_HistoricalBar_ComputesValue() + { + var indicator = new RocpIndicator(); + indicator.Initialize(); + + var now = DateTime.UtcNow; + indicator.HistoricalData.AddBar(now, 100, 105, 95, 102); + + var args = new UpdateArgs(UpdateReason.HistoricalBar); + indicator.ProcessUpdate(args); + + Assert.Equal(1, indicator.LinesSeries[0].Count); + Assert.Equal(1, indicator.LinesSeries[1].Count); + } + + [Fact] + public void ProcessUpdate_NewBar_ComputesValue() + { + var indicator = new RocpIndicator(); + indicator.Initialize(); + + var now = DateTime.UtcNow; + indicator.HistoricalData.AddBar(now, 100, 105, 95, 102); + indicator.HistoricalData.AddBar(now.AddMinutes(1), 102, 108, 100, 106); + + indicator.ProcessUpdate(new UpdateArgs(UpdateReason.HistoricalBar)); + indicator.ProcessUpdate(new UpdateArgs(UpdateReason.NewBar)); + + Assert.Equal(2, indicator.LinesSeries[0].Count); + } + + [Fact] + public void ProcessUpdate_NewTick_ProcessesWithoutError() + { + var indicator = new RocpIndicator(); + indicator.Initialize(); + + var now = DateTime.UtcNow; + indicator.HistoricalData.AddBar(now, 100, 105, 95, 102); + + indicator.ProcessUpdate(new UpdateArgs(UpdateReason.HistoricalBar)); + indicator.ProcessUpdate(new UpdateArgs(UpdateReason.NewTick)); + + Assert.Equal(2, indicator.LinesSeries[0].Count); + } + + [Fact] + public void MultipleUpdates_ProducesCorrectSequence() + { + var indicator = new RocpIndicator(); + indicator.Initialize(); + + var now = DateTime.UtcNow; + + for (int i = 0; i < 20; i++) + { + indicator.HistoricalData.AddBar( + now.AddMinutes(i), + 100 + i * 2, + 105 + i * 2, + 95 + i * 2, + 102 + i * 2); + indicator.ProcessUpdate(new UpdateArgs(UpdateReason.HistoricalBar)); + } + + Assert.Equal(20, indicator.LinesSeries[0].Count); + + for (int i = 0; i < 20; i++) + { + Assert.True(double.IsFinite(indicator.LinesSeries[0].GetValue(i))); + Assert.Equal(0, indicator.LinesSeries[1].GetValue(i)); + } + } + + [Fact] + public void DifferentSourceTypes_Work() + { + var sources = new[] + { + SourceType.Open, + SourceType.High, + SourceType.Low, + SourceType.Close, + SourceType.HL2, + SourceType.HLC3, + }; + + foreach (var source in sources) + { + var indicator = new RocpIndicator { Source = source }; + indicator.Initialize(); + + var now = DateTime.UtcNow; + indicator.HistoricalData.AddBar(now, 100, 110, 90, 105); + indicator.ProcessUpdate(new UpdateArgs(UpdateReason.HistoricalBar)); + + Assert.Equal(1, indicator.LinesSeries[0].Count); + } + } + + [Fact] + public void ShowColdValues_False_SetsNaN() + { + var indicator = new RocpIndicator { ShowColdValues = false }; + indicator.Initialize(); + + var now = DateTime.UtcNow; + indicator.HistoricalData.AddBar(now, 100, 105, 95, 102); + indicator.ProcessUpdate(new UpdateArgs(UpdateReason.HistoricalBar)); + + Assert.True(double.IsNaN(indicator.LinesSeries[0].GetValue(0))); + } + + [Fact] + public void Uptrend_ProducesPositiveRocp() + { + var indicator = new RocpIndicator { Period = 1 }; + indicator.Initialize(); + + var now = DateTime.UtcNow; + + for (int i = 0; i < 10; i++) + { + double price = 100 + i * 5; + indicator.HistoricalData.AddBar(now.AddMinutes(i), price, price + 2, price - 2, price); + indicator.ProcessUpdate(new UpdateArgs(UpdateReason.HistoricalBar)); + } + + double lastRocp = indicator.LinesSeries[0].GetValue(0); + Assert.True(lastRocp > 0); + } + + [Fact] + public void Downtrend_ProducesNegativeRocp() + { + var indicator = new RocpIndicator { Period = 1 }; + indicator.Initialize(); + + var now = DateTime.UtcNow; + + for (int i = 0; i < 10; i++) + { + double price = 200 - i * 5; + indicator.HistoricalData.AddBar(now.AddMinutes(i), price, price + 2, price - 2, price); + indicator.ProcessUpdate(new UpdateArgs(UpdateReason.HistoricalBar)); + } + + double lastRocp = indicator.LinesSeries[0].GetValue(0); + Assert.True(lastRocp < 0); + } + + [Fact] + public void FlatPrices_ProducesZeroRocp() + { + var indicator = new RocpIndicator { Period = 1 }; + indicator.Initialize(); + + var now = DateTime.UtcNow; + + for (int i = 0; i < 5; i++) + { + indicator.HistoricalData.AddBar(now.AddMinutes(i), 100, 105, 95, 100); + indicator.ProcessUpdate(new UpdateArgs(UpdateReason.HistoricalBar)); + } + + double lastRocp = indicator.LinesSeries[0].GetValue(0); + Assert.Equal(0, lastRocp); + } + + [Fact] + public void DifferentPeriods_Work() + { + var periods = new[] { 1, 5, 10, 20 }; + + foreach (var period in periods) + { + var indicator = new RocpIndicator { Period = period }; + indicator.Initialize(); + + var now = DateTime.UtcNow; + + for (int i = 0; i < period + 5; i++) + { + indicator.HistoricalData.AddBar(now.AddMinutes(i), 100 + i, 102 + i, 98 + i, 101 + i); + indicator.ProcessUpdate(new UpdateArgs(UpdateReason.HistoricalBar)); + } + + Assert.Equal(period + 5, indicator.LinesSeries[0].Count); + } + } +} diff --git a/lib/momentum/rocp/Rocp.Tests.cs b/lib/momentum/rocp/tests/Rocp.Tests.cs similarity index 100% rename from lib/momentum/rocp/Rocp.Tests.cs rename to lib/momentum/rocp/tests/Rocp.Tests.cs diff --git a/lib/momentum/rocp/Rocp.Validation.Tests.cs b/lib/momentum/rocp/tests/Rocp.Validation.Tests.cs similarity index 100% rename from lib/momentum/rocp/Rocp.Validation.Tests.cs rename to lib/momentum/rocp/tests/Rocp.Validation.Tests.cs diff --git a/lib/momentum/rocr/Rocr.Quantower.Tests.cs b/lib/momentum/rocr/Rocr.Quantower.Tests.cs deleted file mode 100644 index 3d6eb9e5..00000000 --- a/lib/momentum/rocr/Rocr.Quantower.Tests.cs +++ /dev/null @@ -1,62 +0,0 @@ -using TradingPlatform.BusinessLayer; -using Xunit; - -namespace QuanTAlib.Tests; - -public class RocrIndicatorTests -{ - [Fact] - public void Constructor_InitializesDefaults() - { - var indicator = new RocrIndicator(); - Assert.Equal(9, indicator.Period); - Assert.Equal(SourceType.Close, indicator.Source); - Assert.True(indicator.ShowColdValues); - Assert.Equal("ROCR - Rate of Change Ratio", indicator.Name); - Assert.Contains("current / past", indicator.Description, StringComparison.Ordinal); - Assert.True(indicator.SeparateWindow); - Assert.False(indicator.OnBackGround); - } - - [Fact] - public void ShortName_ReflectsPeriod() - { - var indicator = new RocrIndicator { Period = 14 }; - Assert.Equal("ROCR(14)", indicator.ShortName); - } - - [Fact] - public void MinHistoryDepths_IsPeriodPlusOne() - { - var indicator = new RocrIndicator { Period = 9 }; - Assert.Equal(10, indicator.MinHistoryDepths); - } - - [Fact] - public void MinHistoryDepths_MatchesWatchlistInterface() - { - var indicator = new RocrIndicator { Period = 21 }; - Assert.Equal(22, ((IWatchlistIndicator)indicator).MinHistoryDepths); - } - - [Fact] - public void Period_CanBeSet() - { - var indicator = new RocrIndicator { Period = 20 }; - Assert.Equal(20, indicator.Period); - } - - [Fact] - public void Source_CanBeSet() - { - var indicator = new RocrIndicator { Source = SourceType.Open }; - Assert.Equal(SourceType.Open, indicator.Source); - } - - [Fact] - public void ShowColdValues_CanBeSet() - { - var indicator = new RocrIndicator { ShowColdValues = false }; - Assert.False(indicator.ShowColdValues); - } -} diff --git a/lib/momentum/rocr/tests/Rocr.Quantower.Tests.cs b/lib/momentum/rocr/tests/Rocr.Quantower.Tests.cs new file mode 100644 index 00000000..5bb5bb90 --- /dev/null +++ b/lib/momentum/rocr/tests/Rocr.Quantower.Tests.cs @@ -0,0 +1,265 @@ +using TradingPlatform.BusinessLayer; +using Xunit; + +namespace QuanTAlib.Tests; + +public class RocrIndicatorTests +{ + [Fact] + public void Constructor_InitializesDefaults() + { + var indicator = new RocrIndicator(); + Assert.Equal(9, indicator.Period); + Assert.Equal(SourceType.Close, indicator.Source); + Assert.True(indicator.ShowColdValues); + Assert.Equal("ROCR - Rate of Change Ratio", indicator.Name); + Assert.Contains("current / past", indicator.Description, StringComparison.Ordinal); + Assert.True(indicator.SeparateWindow); + Assert.False(indicator.OnBackGround); + } + + [Fact] + public void ShortName_ReflectsPeriod() + { + var indicator = new RocrIndicator { Period = 14 }; + Assert.Equal("ROCR(14)", indicator.ShortName); + } + + [Fact] + public void MinHistoryDepths_IsPeriodPlusOne() + { + var indicator = new RocrIndicator { Period = 9 }; + Assert.Equal(10, indicator.MinHistoryDepths); + } + + [Fact] + public void MinHistoryDepths_MatchesWatchlistInterface() + { + var indicator = new RocrIndicator { Period = 21 }; + Assert.Equal(22, ((IWatchlistIndicator)indicator).MinHistoryDepths); + } + + [Fact] + public void Period_CanBeSet() + { + var indicator = new RocrIndicator { Period = 20 }; + Assert.Equal(20, indicator.Period); + } + + [Fact] + public void Source_CanBeSet() + { + var indicator = new RocrIndicator { Source = SourceType.Open }; + Assert.Equal(SourceType.Open, indicator.Source); + } + + [Fact] + public void ShowColdValues_CanBeSet() + { + var indicator = new RocrIndicator { ShowColdValues = false }; + Assert.False(indicator.ShowColdValues); + } + + [Fact] + public void Initialize_CreatesLineSeries() + { + var indicator = new RocrIndicator(); + indicator.Initialize(); + + Assert.Equal(2, indicator.LinesSeries.Count); + Assert.Equal("ROCR", indicator.LinesSeries[0].Name); + Assert.Equal("One", indicator.LinesSeries[1].Name); + } + + [Fact] + public void ProcessUpdate_HistoricalBar_ComputesValue() + { + var indicator = new RocrIndicator(); + indicator.Initialize(); + + var now = DateTime.UtcNow; + indicator.HistoricalData.AddBar(now, 100, 105, 95, 102); + + var args = new UpdateArgs(UpdateReason.HistoricalBar); + indicator.ProcessUpdate(args); + + Assert.Equal(1, indicator.LinesSeries[0].Count); + Assert.Equal(1, indicator.LinesSeries[1].Count); + } + + [Fact] + public void ProcessUpdate_NewBar_ComputesValue() + { + var indicator = new RocrIndicator(); + indicator.Initialize(); + + var now = DateTime.UtcNow; + indicator.HistoricalData.AddBar(now, 100, 105, 95, 102); + indicator.HistoricalData.AddBar(now.AddMinutes(1), 102, 108, 100, 106); + + indicator.ProcessUpdate(new UpdateArgs(UpdateReason.HistoricalBar)); + indicator.ProcessUpdate(new UpdateArgs(UpdateReason.NewBar)); + + Assert.Equal(2, indicator.LinesSeries[0].Count); + } + + [Fact] + public void ProcessUpdate_NewTick_ProcessesWithoutError() + { + var indicator = new RocrIndicator(); + indicator.Initialize(); + + var now = DateTime.UtcNow; + indicator.HistoricalData.AddBar(now, 100, 105, 95, 102); + + indicator.ProcessUpdate(new UpdateArgs(UpdateReason.HistoricalBar)); + indicator.ProcessUpdate(new UpdateArgs(UpdateReason.NewTick)); + + Assert.Equal(2, indicator.LinesSeries[0].Count); + } + + [Fact] + public void MultipleUpdates_ProducesCorrectSequence() + { + var indicator = new RocrIndicator(); + indicator.Initialize(); + + var now = DateTime.UtcNow; + + for (int i = 0; i < 20; i++) + { + indicator.HistoricalData.AddBar( + now.AddMinutes(i), + 100 + i * 2, + 105 + i * 2, + 95 + i * 2, + 102 + i * 2); + indicator.ProcessUpdate(new UpdateArgs(UpdateReason.HistoricalBar)); + } + + Assert.Equal(20, indicator.LinesSeries[0].Count); + + for (int i = 0; i < 20; i++) + { + Assert.True(double.IsFinite(indicator.LinesSeries[0].GetValue(i))); + Assert.Equal(1.0, indicator.LinesSeries[1].GetValue(i)); + } + } + + [Fact] + public void DifferentSourceTypes_Work() + { + var sources = new[] + { + SourceType.Open, + SourceType.High, + SourceType.Low, + SourceType.Close, + SourceType.HL2, + SourceType.HLC3, + }; + + foreach (var source in sources) + { + var indicator = new RocrIndicator { Source = source }; + indicator.Initialize(); + + var now = DateTime.UtcNow; + indicator.HistoricalData.AddBar(now, 100, 110, 90, 105); + indicator.ProcessUpdate(new UpdateArgs(UpdateReason.HistoricalBar)); + + Assert.Equal(1, indicator.LinesSeries[0].Count); + } + } + + [Fact] + public void ShowColdValues_False_SetsNaN() + { + var indicator = new RocrIndicator { ShowColdValues = false }; + indicator.Initialize(); + + var now = DateTime.UtcNow; + indicator.HistoricalData.AddBar(now, 100, 105, 95, 102); + indicator.ProcessUpdate(new UpdateArgs(UpdateReason.HistoricalBar)); + + Assert.True(double.IsNaN(indicator.LinesSeries[0].GetValue(0))); + } + + [Fact] + public void Uptrend_ProducesRatioAboveOne() + { + var indicator = new RocrIndicator { Period = 1 }; + indicator.Initialize(); + + var now = DateTime.UtcNow; + + for (int i = 0; i < 10; i++) + { + double price = 100 + i * 5; + indicator.HistoricalData.AddBar(now.AddMinutes(i), price, price + 2, price - 2, price); + indicator.ProcessUpdate(new UpdateArgs(UpdateReason.HistoricalBar)); + } + + double lastRocr = indicator.LinesSeries[0].GetValue(0); + Assert.True(lastRocr > 1.0); + } + + [Fact] + public void Downtrend_ProducesRatioBelowOne() + { + var indicator = new RocrIndicator { Period = 1 }; + indicator.Initialize(); + + var now = DateTime.UtcNow; + + for (int i = 0; i < 10; i++) + { + double price = 200 - i * 5; + indicator.HistoricalData.AddBar(now.AddMinutes(i), price, price + 2, price - 2, price); + indicator.ProcessUpdate(new UpdateArgs(UpdateReason.HistoricalBar)); + } + + double lastRocr = indicator.LinesSeries[0].GetValue(0); + Assert.True(lastRocr < 1.0); + } + + [Fact] + public void FlatPrices_ProducesRatioOfOne() + { + var indicator = new RocrIndicator { Period = 1 }; + indicator.Initialize(); + + var now = DateTime.UtcNow; + + for (int i = 0; i < 5; i++) + { + indicator.HistoricalData.AddBar(now.AddMinutes(i), 100, 105, 95, 100); + indicator.ProcessUpdate(new UpdateArgs(UpdateReason.HistoricalBar)); + } + + double lastRocr = indicator.LinesSeries[0].GetValue(0); + Assert.Equal(1.0, lastRocr, 10); + } + + [Fact] + public void DifferentPeriods_Work() + { + var periods = new[] { 1, 5, 10, 20 }; + + foreach (var period in periods) + { + var indicator = new RocrIndicator { Period = period }; + indicator.Initialize(); + + var now = DateTime.UtcNow; + + for (int i = 0; i < period + 5; i++) + { + indicator.HistoricalData.AddBar(now.AddMinutes(i), 100 + i, 102 + i, 98 + i, 101 + i); + indicator.ProcessUpdate(new UpdateArgs(UpdateReason.HistoricalBar)); + } + + Assert.Equal(period + 5, indicator.LinesSeries[0].Count); + } + } +} diff --git a/lib/momentum/rocr/Rocr.Tests.cs b/lib/momentum/rocr/tests/Rocr.Tests.cs similarity index 100% rename from lib/momentum/rocr/Rocr.Tests.cs rename to lib/momentum/rocr/tests/Rocr.Tests.cs diff --git a/lib/momentum/rocr/Rocr.Validation.Tests.cs b/lib/momentum/rocr/tests/Rocr.Validation.Tests.cs similarity index 100% rename from lib/momentum/rocr/Rocr.Validation.Tests.cs rename to lib/momentum/rocr/tests/Rocr.Validation.Tests.cs diff --git a/lib/momentum/rsi/Rsi.md b/lib/momentum/rsi/Rsi.md index 626c623a..a2756fb6 100644 --- a/lib/momentum/rsi/Rsi.md +++ b/lib/momentum/rsi/Rsi.md @@ -230,91 +230,6 @@ var rsi = new Rsi(14); rsi.Prime(historicalPrices); // Ready for live data ``` -## C# Implementation Considerations - -### Dual RMA Architecture - -RSI maintains two separate RMA instances for gains and losses: - -```csharp -private readonly Rma _avgGain; -private readonly Rma _avgLoss; -``` - -Each RMA handles its own state management and warmup compensation. - -### State Management - -```csharp -private double _prevValue; // Previous close for change calculation -private double _p_prevValue; // Backup for bar correction -``` - -Bar correction requires rolling back both the previous value and both RMA states: - -```csharp -if (isNew) -{ - _p_prevValue = _prevValue; -} -else -{ - _prevValue = _p_prevValue; -} -// RMAs handle their own isNew logic -_avgGain.Update(new TValue(input.Time, gain), isNew); -_avgLoss.Update(new TValue(input.Time, loss), isNew); -``` - -### SIMD Vectorization in Batch - -The `Calculate` method uses `System.Numerics.Vector` for gain/loss classification: - -```csharp -var vCurrent = new Vector(source.Slice(i, vectorSize)); -var vPrev = new Vector(source.Slice(i - 1, vectorSize)); -var vChange = vCurrent - vPrev; - -var vGain = Vector.Max(vChange, vZero); -var vLoss = Vector.Max(-vChange, vZero); -``` - -The final RSI calculation also uses SIMD with `Vector.ConditionalSelect` for edge case handling: - -```csharp -var vResult = Vector.ConditionalSelect(vLossIsZero, v100, vRsi); -vResult = Vector.ConditionalSelect(vFlat, v50, vResult); -``` - -### ArrayPool for Temporary Buffers - -Batch processing rents arrays from the shared pool to avoid allocations: - -```csharp -double[] gains = ArrayPool.Shared.Rent(len); -double[] losses = ArrayPool.Shared.Rent(len); -try -{ - // ... calculations ... -} -finally -{ - ArrayPool.Shared.Return(gains); - ArrayPool.Shared.Return(losses); -} -``` - -### Memory Layout - -| Component | Size | Purpose | -| :-------- | ---: | :------ | -| `_avgGain` (Rma) | ~40 bytes | Gain smoothing | -| `_avgLoss` (Rma) | ~40 bytes | Loss smoothing | -| `_prevValue` | 8 bytes | Previous close | -| `_p_prevValue` | 8 bytes | Bar correction backup | -| `_period` | 4 bytes | Period parameter | -| **Total per instance** | **~100 bytes** | No period-dependent allocations | - ## References - Wilder, J. W. (1978). *New Concepts in Technical Trading Systems*. Trend Research. Chapter: Relative Strength Index. diff --git a/lib/momentum/rsi/Rsi.Quantower.Tests.cs b/lib/momentum/rsi/tests/Rsi.Quantower.Tests.cs similarity index 100% rename from lib/momentum/rsi/Rsi.Quantower.Tests.cs rename to lib/momentum/rsi/tests/Rsi.Quantower.Tests.cs diff --git a/lib/momentum/rsi/Rsi.Tests.cs b/lib/momentum/rsi/tests/Rsi.Tests.cs similarity index 100% rename from lib/momentum/rsi/Rsi.Tests.cs rename to lib/momentum/rsi/tests/Rsi.Tests.cs diff --git a/lib/momentum/rsi/Rsi.Validation.Tests.cs b/lib/momentum/rsi/tests/Rsi.Validation.Tests.cs similarity index 100% rename from lib/momentum/rsi/Rsi.Validation.Tests.cs rename to lib/momentum/rsi/tests/Rsi.Validation.Tests.cs diff --git a/lib/momentum/rsx/Rsx.md b/lib/momentum/rsx/Rsx.md index 8307ae94..cd154394 100644 --- a/lib/momentum/rsx/Rsx.md +++ b/lib/momentum/rsx/Rsx.md @@ -312,63 +312,6 @@ rsx.Pub += (sender, args) => }; ``` -## C# Implementation Considerations - -### FMA Pattern for Filter Updates - -Each filter uses `Math.FusedMultiplyAdd` for precision and performance: - -```csharp -// EMA update: new = old * decay + alpha * input -m1_1 = Math.FusedMultiplyAdd(_state.M1_1, _decay, _alpha * momentum); -m1_2 = Math.FusedMultiplyAdd(_state.M1_2, _decay, _alpha * m1_1); - -// Stage output: (3 * f1 - f2) * 0.5 -double m1_out = Math.FusedMultiplyAdd(3.0, m1_1, -m1_2) * 0.5; -``` - -FMA reduces rounding error in the 12-filter cascade where small errors would otherwise accumulate. - -### State Struct Layout - -```csharp -[StructLayout(LayoutKind.Auto)] -private record struct State -{ - // Momentum filters (3 stages × 2 filters) - public double M1_1, M1_2; - public double M2_1, M2_2; - public double M3_1, M3_2; - - // Absolute Momentum filters (3 stages × 2 filters) - public double A1_1, A1_2; - public double A2_1, A2_2; - public double A3_1, A3_2; - - public double LastPrice; - public double LastValidValue; - public bool IsInitialized; -} -``` - -`LayoutKind.Auto` allows runtime to optimize field alignment. Record struct provides value semantics for efficient copying during bar correction. - -### Division Guard - -```csharp -if (smoothedAbsMomentum > 1e-10) -{ - double v4 = (smoothedMomentum / smoothedAbsMomentum + 1.0) * 50.0; - rsx = Math.Clamp(v4, 0.0, 100.0); -} -else -{ - rsx = 50.0; // Neutral when no momentum -} -``` - -Epsilon threshold prevents division by zero while maintaining meaningful output during flat markets. - ## References - Jurik, M. (1990s). "RSX: Relative Strength Quality Index." Jurik Research. Proprietary documentation. diff --git a/lib/momentum/rsx/Rsx.Quantower.Tests.cs b/lib/momentum/rsx/tests/Rsx.Quantower.Tests.cs similarity index 100% rename from lib/momentum/rsx/Rsx.Quantower.Tests.cs rename to lib/momentum/rsx/tests/Rsx.Quantower.Tests.cs diff --git a/lib/momentum/rsx/Rsx.Repro.Tests.cs b/lib/momentum/rsx/tests/Rsx.Repro.Tests.cs similarity index 100% rename from lib/momentum/rsx/Rsx.Repro.Tests.cs rename to lib/momentum/rsx/tests/Rsx.Repro.Tests.cs diff --git a/lib/momentum/rsx/Rsx.Tests.cs b/lib/momentum/rsx/tests/Rsx.Tests.cs similarity index 100% rename from lib/momentum/rsx/Rsx.Tests.cs rename to lib/momentum/rsx/tests/Rsx.Tests.cs diff --git a/lib/momentum/rsx/Rsx.Validation.Tests.cs b/lib/momentum/rsx/tests/Rsx.Validation.Tests.cs similarity index 100% rename from lib/momentum/rsx/Rsx.Validation.Tests.cs rename to lib/momentum/rsx/tests/Rsx.Validation.Tests.cs diff --git a/lib/momentum/sam/Sam.Quantower.Tests.cs b/lib/momentum/sam/tests/Sam.Quantower.Tests.cs similarity index 100% rename from lib/momentum/sam/Sam.Quantower.Tests.cs rename to lib/momentum/sam/tests/Sam.Quantower.Tests.cs diff --git a/lib/momentum/sam/Sam.Tests.cs b/lib/momentum/sam/tests/Sam.Tests.cs similarity index 100% rename from lib/momentum/sam/Sam.Tests.cs rename to lib/momentum/sam/tests/Sam.Tests.cs diff --git a/lib/momentum/sam/Sam.Validation.Tests.cs b/lib/momentum/sam/tests/Sam.Validation.Tests.cs similarity index 100% rename from lib/momentum/sam/Sam.Validation.Tests.cs rename to lib/momentum/sam/tests/Sam.Validation.Tests.cs diff --git a/lib/momentum/tsi/Tsi.Quantower.Tests.cs b/lib/momentum/tsi/tests/Tsi.Quantower.Tests.cs similarity index 100% rename from lib/momentum/tsi/Tsi.Quantower.Tests.cs rename to lib/momentum/tsi/tests/Tsi.Quantower.Tests.cs diff --git a/lib/momentum/tsi/Tsi.Tests.cs b/lib/momentum/tsi/tests/Tsi.Tests.cs similarity index 100% rename from lib/momentum/tsi/Tsi.Tests.cs rename to lib/momentum/tsi/tests/Tsi.Tests.cs diff --git a/lib/momentum/tsi/Tsi.Validation.Tests.cs b/lib/momentum/tsi/tests/Tsi.Validation.Tests.cs similarity index 100% rename from lib/momentum/tsi/Tsi.Validation.Tests.cs rename to lib/momentum/tsi/tests/Tsi.Validation.Tests.cs diff --git a/lib/momentum/vel/Vel.md b/lib/momentum/vel/Vel.md index f719c8a1..96962b8f 100644 --- a/lib/momentum/vel/Vel.md +++ b/lib/momentum/vel/Vel.md @@ -303,78 +303,6 @@ foreach (var bar in bars) } ``` -## C# Implementation Considerations - -### Composition Pattern - -VEL composes PWMA and WMA instances rather than reimplementing their logic: - -```csharp -private readonly Pwma _pwma; -private readonly Wma _wma; - -public Vel(int period) -{ - _pwma = new Pwma(period); - _wma = new Wma(period); - // ... -} -``` - -This ensures VEL automatically benefits from any optimizations to PWMA or WMA. - -### Update Delegation - -```csharp -public TValue Update(TValue input, bool isNew = true) -{ - var pwma = _pwma.Update(input, isNew); - var wma = _wma.Update(input, isNew); - - Last = new TValue(input.Time, pwma.Value - wma.Value); - Pub?.Invoke(this, new TValueEventArgs { Value = Last, IsNew = isNew }); - return Last; -} -``` - -Single subtraction after delegated updates. No additional state management required. - -### SIMD Batch Optimization - -```csharp -public static void Batch(ReadOnlySpan source, Span output, int period) -{ - // stackalloc for intermediate arrays (threshold: 1024 elements) - Span pwma = source.Length <= 1024 - ? stackalloc double[source.Length] - : new double[source.Length]; - Span wma = source.Length <= 1024 - ? stackalloc double[source.Length] - : new double[source.Length]; - - Pwma.Calculate(source, pwma, period); - Wma.Batch(source, wma, period); - - // SIMD-accelerated subtraction - SimdExtensions.Subtract(pwma, wma, output); -} -``` - -The 1024-element threshold (8KB for doubles) keeps stack allocation within safe limits. - -### Reset Propagation - -```csharp -public void Reset() -{ - _pwma.Reset(); - _wma.Reset(); - Last = default; -} -``` - -Reset propagates to composed indicators, ensuring clean state. - ## References - Jurik, M. (1990s). "Jurik Velocity (VEL)." Jurik Research. Proprietary documentation. diff --git a/lib/momentum/vel/Vel.Quantower.Tests.cs b/lib/momentum/vel/tests/Vel.Quantower.Tests.cs similarity index 100% rename from lib/momentum/vel/Vel.Quantower.Tests.cs rename to lib/momentum/vel/tests/Vel.Quantower.Tests.cs diff --git a/lib/momentum/vel/Vel.Tests.cs b/lib/momentum/vel/tests/Vel.Tests.cs similarity index 100% rename from lib/momentum/vel/Vel.Tests.cs rename to lib/momentum/vel/tests/Vel.Tests.cs diff --git a/lib/momentum/vel/Vel.Validation.Tests.cs b/lib/momentum/vel/tests/Vel.Validation.Tests.cs similarity index 100% rename from lib/momentum/vel/Vel.Validation.Tests.cs rename to lib/momentum/vel/tests/Vel.Validation.Tests.cs diff --git a/lib/numerics/accel/Accel.Tests.cs b/lib/numerics/accel/tests/Accel.Tests.cs similarity index 100% rename from lib/numerics/accel/Accel.Tests.cs rename to lib/numerics/accel/tests/Accel.Tests.cs diff --git a/lib/numerics/accel/Accel.Validation.Tests.cs b/lib/numerics/accel/tests/Accel.Validation.Tests.cs similarity index 100% rename from lib/numerics/accel/Accel.Validation.Tests.cs rename to lib/numerics/accel/tests/Accel.Validation.Tests.cs diff --git a/lib/numerics/betadist/Betadist.Tests.cs b/lib/numerics/betadist/tests/Betadist.Tests.cs similarity index 100% rename from lib/numerics/betadist/Betadist.Tests.cs rename to lib/numerics/betadist/tests/Betadist.Tests.cs diff --git a/lib/numerics/betadist/Betadist.Validation.Tests.cs b/lib/numerics/betadist/tests/Betadist.Validation.Tests.cs similarity index 100% rename from lib/numerics/betadist/Betadist.Validation.Tests.cs rename to lib/numerics/betadist/tests/Betadist.Validation.Tests.cs diff --git a/lib/numerics/binomdist/Binomdist.Tests.cs b/lib/numerics/binomdist/tests/Binomdist.Tests.cs similarity index 100% rename from lib/numerics/binomdist/Binomdist.Tests.cs rename to lib/numerics/binomdist/tests/Binomdist.Tests.cs diff --git a/lib/numerics/binomdist/Binomdist.Validation.Tests.cs b/lib/numerics/binomdist/tests/Binomdist.Validation.Tests.cs similarity index 100% rename from lib/numerics/binomdist/Binomdist.Validation.Tests.cs rename to lib/numerics/binomdist/tests/Binomdist.Validation.Tests.cs diff --git a/lib/numerics/change/Change.Tests.cs b/lib/numerics/change/tests/Change.Tests.cs similarity index 100% rename from lib/numerics/change/Change.Tests.cs rename to lib/numerics/change/tests/Change.Tests.cs diff --git a/lib/numerics/change/Change.Validation.Tests.cs b/lib/numerics/change/tests/Change.Validation.Tests.cs similarity index 100% rename from lib/numerics/change/Change.Validation.Tests.cs rename to lib/numerics/change/tests/Change.Validation.Tests.cs diff --git a/lib/numerics/cwt/Cwt.Tests.cs b/lib/numerics/cwt/tests/Cwt.Tests.cs similarity index 100% rename from lib/numerics/cwt/Cwt.Tests.cs rename to lib/numerics/cwt/tests/Cwt.Tests.cs diff --git a/lib/numerics/cwt/Cwt.Validation.Tests.cs b/lib/numerics/cwt/tests/Cwt.Validation.Tests.cs similarity index 100% rename from lib/numerics/cwt/Cwt.Validation.Tests.cs rename to lib/numerics/cwt/tests/Cwt.Validation.Tests.cs diff --git a/lib/numerics/decay/Decay.Quantower.Tests.cs b/lib/numerics/decay/tests/Decay.Quantower.Tests.cs similarity index 100% rename from lib/numerics/decay/Decay.Quantower.Tests.cs rename to lib/numerics/decay/tests/Decay.Quantower.Tests.cs diff --git a/lib/numerics/decay/Decay.Tests.cs b/lib/numerics/decay/tests/Decay.Tests.cs similarity index 100% rename from lib/numerics/decay/Decay.Tests.cs rename to lib/numerics/decay/tests/Decay.Tests.cs diff --git a/lib/numerics/decay/Decay.Validation.Tests.cs b/lib/numerics/decay/tests/Decay.Validation.Tests.cs similarity index 100% rename from lib/numerics/decay/Decay.Validation.Tests.cs rename to lib/numerics/decay/tests/Decay.Validation.Tests.cs diff --git a/lib/numerics/dwt/Dwt.Tests.cs b/lib/numerics/dwt/tests/Dwt.Tests.cs similarity index 100% rename from lib/numerics/dwt/Dwt.Tests.cs rename to lib/numerics/dwt/tests/Dwt.Tests.cs diff --git a/lib/numerics/dwt/Dwt.Validation.Tests.cs b/lib/numerics/dwt/tests/Dwt.Validation.Tests.cs similarity index 100% rename from lib/numerics/dwt/Dwt.Validation.Tests.cs rename to lib/numerics/dwt/tests/Dwt.Validation.Tests.cs diff --git a/lib/numerics/edecay/Edecay.Quantower.Tests.cs b/lib/numerics/edecay/tests/Edecay.Quantower.Tests.cs similarity index 100% rename from lib/numerics/edecay/Edecay.Quantower.Tests.cs rename to lib/numerics/edecay/tests/Edecay.Quantower.Tests.cs diff --git a/lib/numerics/edecay/Edecay.Tests.cs b/lib/numerics/edecay/tests/Edecay.Tests.cs similarity index 100% rename from lib/numerics/edecay/Edecay.Tests.cs rename to lib/numerics/edecay/tests/Edecay.Tests.cs diff --git a/lib/numerics/edecay/Edecay.Validation.Tests.cs b/lib/numerics/edecay/tests/Edecay.Validation.Tests.cs similarity index 100% rename from lib/numerics/edecay/Edecay.Validation.Tests.cs rename to lib/numerics/edecay/tests/Edecay.Validation.Tests.cs diff --git a/lib/numerics/expdist/Expdist.Tests.cs b/lib/numerics/expdist/tests/Expdist.Tests.cs similarity index 100% rename from lib/numerics/expdist/Expdist.Tests.cs rename to lib/numerics/expdist/tests/Expdist.Tests.cs diff --git a/lib/numerics/expdist/Expdist.Validation.Tests.cs b/lib/numerics/expdist/tests/Expdist.Validation.Tests.cs similarity index 100% rename from lib/numerics/expdist/Expdist.Validation.Tests.cs rename to lib/numerics/expdist/tests/Expdist.Validation.Tests.cs diff --git a/lib/numerics/exptrans/Exptrans.Tests.cs b/lib/numerics/exptrans/tests/Exptrans.Tests.cs similarity index 100% rename from lib/numerics/exptrans/Exptrans.Tests.cs rename to lib/numerics/exptrans/tests/Exptrans.Tests.cs diff --git a/lib/numerics/exptrans/Exptrans.Validation.Tests.cs b/lib/numerics/exptrans/tests/Exptrans.Validation.Tests.cs similarity index 100% rename from lib/numerics/exptrans/Exptrans.Validation.Tests.cs rename to lib/numerics/exptrans/tests/Exptrans.Validation.Tests.cs diff --git a/lib/numerics/fdist/Fdist.Tests.cs b/lib/numerics/fdist/tests/Fdist.Tests.cs similarity index 100% rename from lib/numerics/fdist/Fdist.Tests.cs rename to lib/numerics/fdist/tests/Fdist.Tests.cs diff --git a/lib/numerics/fdist/Fdist.Validation.Tests.cs b/lib/numerics/fdist/tests/Fdist.Validation.Tests.cs similarity index 100% rename from lib/numerics/fdist/Fdist.Validation.Tests.cs rename to lib/numerics/fdist/tests/Fdist.Validation.Tests.cs diff --git a/lib/numerics/fft/Fft.Tests.cs b/lib/numerics/fft/tests/Fft.Tests.cs similarity index 100% rename from lib/numerics/fft/Fft.Tests.cs rename to lib/numerics/fft/tests/Fft.Tests.cs diff --git a/lib/numerics/fft/Fft.Validation.Tests.cs b/lib/numerics/fft/tests/Fft.Validation.Tests.cs similarity index 100% rename from lib/numerics/fft/Fft.Validation.Tests.cs rename to lib/numerics/fft/tests/Fft.Validation.Tests.cs diff --git a/lib/numerics/gammadist/Gammadist.Tests.cs b/lib/numerics/gammadist/tests/Gammadist.Tests.cs similarity index 100% rename from lib/numerics/gammadist/Gammadist.Tests.cs rename to lib/numerics/gammadist/tests/Gammadist.Tests.cs diff --git a/lib/numerics/gammadist/Gammadist.Validation.Tests.cs b/lib/numerics/gammadist/tests/Gammadist.Validation.Tests.cs similarity index 100% rename from lib/numerics/gammadist/Gammadist.Validation.Tests.cs rename to lib/numerics/gammadist/tests/Gammadist.Validation.Tests.cs diff --git a/lib/numerics/highest/Highest.Tests.cs b/lib/numerics/highest/tests/Highest.Tests.cs similarity index 100% rename from lib/numerics/highest/Highest.Tests.cs rename to lib/numerics/highest/tests/Highest.Tests.cs diff --git a/lib/numerics/highest/Highest.Validation.Tests.cs b/lib/numerics/highest/tests/Highest.Validation.Tests.cs similarity index 100% rename from lib/numerics/highest/Highest.Validation.Tests.cs rename to lib/numerics/highest/tests/Highest.Validation.Tests.cs diff --git a/lib/numerics/ifft/Ifft.Tests.cs b/lib/numerics/ifft/tests/Ifft.Tests.cs similarity index 100% rename from lib/numerics/ifft/Ifft.Tests.cs rename to lib/numerics/ifft/tests/Ifft.Tests.cs diff --git a/lib/numerics/ifft/Ifft.Validation.Tests.cs b/lib/numerics/ifft/tests/Ifft.Validation.Tests.cs similarity index 100% rename from lib/numerics/ifft/Ifft.Validation.Tests.cs rename to lib/numerics/ifft/tests/Ifft.Validation.Tests.cs diff --git a/lib/numerics/jerk/Jerk.Tests.cs b/lib/numerics/jerk/tests/Jerk.Tests.cs similarity index 100% rename from lib/numerics/jerk/Jerk.Tests.cs rename to lib/numerics/jerk/tests/Jerk.Tests.cs diff --git a/lib/numerics/jerk/Jerk.Validation.Tests.cs b/lib/numerics/jerk/tests/Jerk.Validation.Tests.cs similarity index 100% rename from lib/numerics/jerk/Jerk.Validation.Tests.cs rename to lib/numerics/jerk/tests/Jerk.Validation.Tests.cs diff --git a/lib/numerics/lineartrans/Lineartrans.Tests.cs b/lib/numerics/lineartrans/tests/Lineartrans.Tests.cs similarity index 100% rename from lib/numerics/lineartrans/Lineartrans.Tests.cs rename to lib/numerics/lineartrans/tests/Lineartrans.Tests.cs diff --git a/lib/numerics/lineartrans/Lineartrans.Validation.Tests.cs b/lib/numerics/lineartrans/tests/Lineartrans.Validation.Tests.cs similarity index 100% rename from lib/numerics/lineartrans/Lineartrans.Validation.Tests.cs rename to lib/numerics/lineartrans/tests/Lineartrans.Validation.Tests.cs diff --git a/lib/numerics/lognormdist/Lognormdist.Tests.cs b/lib/numerics/lognormdist/tests/Lognormdist.Tests.cs similarity index 100% rename from lib/numerics/lognormdist/Lognormdist.Tests.cs rename to lib/numerics/lognormdist/tests/Lognormdist.Tests.cs diff --git a/lib/numerics/lognormdist/Lognormdist.Validation.Tests.cs b/lib/numerics/lognormdist/tests/Lognormdist.Validation.Tests.cs similarity index 100% rename from lib/numerics/lognormdist/Lognormdist.Validation.Tests.cs rename to lib/numerics/lognormdist/tests/Lognormdist.Validation.Tests.cs diff --git a/lib/numerics/logtrans/Logtrans.Tests.cs b/lib/numerics/logtrans/tests/Logtrans.Tests.cs similarity index 100% rename from lib/numerics/logtrans/Logtrans.Tests.cs rename to lib/numerics/logtrans/tests/Logtrans.Tests.cs diff --git a/lib/numerics/logtrans/Logtrans.Validation.Tests.cs b/lib/numerics/logtrans/tests/Logtrans.Validation.Tests.cs similarity index 100% rename from lib/numerics/logtrans/Logtrans.Validation.Tests.cs rename to lib/numerics/logtrans/tests/Logtrans.Validation.Tests.cs diff --git a/lib/numerics/lowest/Lowest.Tests.cs b/lib/numerics/lowest/tests/Lowest.Tests.cs similarity index 100% rename from lib/numerics/lowest/Lowest.Tests.cs rename to lib/numerics/lowest/tests/Lowest.Tests.cs diff --git a/lib/numerics/lowest/Lowest.Validation.Tests.cs b/lib/numerics/lowest/tests/Lowest.Validation.Tests.cs similarity index 100% rename from lib/numerics/lowest/Lowest.Validation.Tests.cs rename to lib/numerics/lowest/tests/Lowest.Validation.Tests.cs diff --git a/lib/numerics/maxindex/Maxindex.Quantower.cs b/lib/numerics/maxindex/Maxindex.Quantower.cs new file mode 100644 index 00000000..97666d2d --- /dev/null +++ b/lib/numerics/maxindex/Maxindex.Quantower.cs @@ -0,0 +1,59 @@ +using System.Drawing; +using System.Runtime.CompilerServices; +using TradingPlatform.BusinessLayer; + +namespace QuanTAlib; + +/// +/// MAXINDEX (Rolling Maximum Index) Quantower indicator. +/// Returns the bars-ago position of the maximum value within a rolling window. +/// +[SkipLocalsInit] +public class MaxindexIndicator : Indicator, IWatchlistIndicator +{ + [InputParameter("Period", sortIndex: 1, 2, 1000, 1, 0)] + public int Period { get; set; } = 14; + + [IndicatorExtensions.DataSourceInput] + public SourceType Source { get; set; } = SourceType.Close; + + [InputParameter("Show cold values", sortIndex: 21)] + public bool ShowColdValues { get; set; } = true; + + private Maxindex _indicator = null!; + protected LineSeries Series; + protected string SourceName = null!; + private Func _priceSelector = null!; + + public int MinHistoryDepths => Period; + int IWatchlistIndicator.MinHistoryDepths => MinHistoryDepths; + + public override string ShortName => $"MAXINDEX({Period})"; + + public MaxindexIndicator() + { + OnBackGround = false; + SeparateWindow = true; + SourceName = Source.ToString(); + Name = "MAXINDEX - Rolling Maximum Index"; + Description = "Returns the bars-ago position of the maximum value within a rolling lookback window."; + Series = new LineSeries(name: "MAXINDEX", color: IndicatorExtensions.Momentum, width: 2, style: LineStyle.Histogramm); + AddLineSeries(Series); + } + + protected override void OnInit() + { + _indicator = new Maxindex(Period); + SourceName = Source.ToString(); + _priceSelector = Source.GetPriceSelector(); + base.OnInit(); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + protected override void OnUpdate(UpdateArgs args) + { + var item = HistoricalData[Count - 1, SeekOriginHistory.Begin]; + TValue result = _indicator.Update(new TValue(item.TimeLeft.Ticks, _priceSelector(item)), isNew: args.IsNewBar()); + Series.SetValue(result.Value, _indicator.IsHot, ShowColdValues); + } +} diff --git a/lib/numerics/maxindex/tests/Maxindex.Quantower.Tests.cs b/lib/numerics/maxindex/tests/Maxindex.Quantower.Tests.cs new file mode 100644 index 00000000..aa48f442 --- /dev/null +++ b/lib/numerics/maxindex/tests/Maxindex.Quantower.Tests.cs @@ -0,0 +1,223 @@ +using TradingPlatform.BusinessLayer; + +namespace QuanTAlib.Tests; + +public class MaxindexIndicatorTests +{ + [Fact] + public void MaxindexIndicator_Constructor_SetsDefaults() + { + var indicator = new MaxindexIndicator(); + + Assert.Equal(14, indicator.Period); + Assert.Equal(SourceType.Close, indicator.Source); + Assert.True(indicator.ShowColdValues); + Assert.Equal("MAXINDEX - Rolling Maximum Index", indicator.Name); + Assert.True(indicator.SeparateWindow); + Assert.False(indicator.OnBackGround); + } + + [Fact] + public void MaxindexIndicator_MinHistoryDepths_EqualsPeriod() + { + var indicator = new MaxindexIndicator { Period = 20 }; + + Assert.Equal(20, indicator.MinHistoryDepths); + Assert.Equal(20, ((IWatchlistIndicator)indicator).MinHistoryDepths); + } + + [Fact] + public void MaxindexIndicator_ShortName_IncludesPeriod() + { + var indicator = new MaxindexIndicator { Period = 10 }; + + Assert.Equal("MAXINDEX(10)", indicator.ShortName); + } + + [Fact] + public void MaxindexIndicator_Initialize_CreatesLineSeries() + { + var indicator = new MaxindexIndicator { Period = 5 }; + indicator.Initialize(); + + Assert.Single(indicator.LinesSeries); + } + + [Fact] + public void MaxindexIndicator_ProcessUpdate_HistoricalBar_ComputesValue() + { + var indicator = new MaxindexIndicator { Period = 5 }; + indicator.Initialize(); + + var now = DateTime.UtcNow; + indicator.HistoricalData.AddBar(now, 100, 105, 95, 102); + + var args = new UpdateArgs(UpdateReason.HistoricalBar); + indicator.ProcessUpdate(args); + + Assert.Equal(1, indicator.LinesSeries[0].Count); + Assert.True(double.IsFinite(indicator.LinesSeries[0].GetValue(0))); + } + + [Fact] + public void MaxindexIndicator_ProcessUpdate_NewBar_ComputesValue() + { + var indicator = new MaxindexIndicator { Period = 5 }; + indicator.Initialize(); + + var now = DateTime.UtcNow; + indicator.HistoricalData.AddBar(now, 100, 105, 95, 102); + indicator.HistoricalData.AddBar(now.AddMinutes(1), 102, 108, 100, 106); + + indicator.ProcessUpdate(new UpdateArgs(UpdateReason.HistoricalBar)); + indicator.ProcessUpdate(new UpdateArgs(UpdateReason.NewBar)); + + Assert.Equal(2, indicator.LinesSeries[0].Count); + } + + [Fact] + public void MaxindexIndicator_ProcessUpdate_NewTick_ProcessesWithoutError() + { + var indicator = new MaxindexIndicator { Period = 5 }; + indicator.Initialize(); + + var now = DateTime.UtcNow; + indicator.HistoricalData.AddBar(now, 100, 105, 95, 102); + + indicator.ProcessUpdate(new UpdateArgs(UpdateReason.HistoricalBar)); + indicator.ProcessUpdate(new UpdateArgs(UpdateReason.NewTick)); + + Assert.Equal(2, indicator.LinesSeries[0].Count); + } + + [Fact] + public void MaxindexIndicator_MultipleUpdates_ProducesCorrectSequence() + { + var indicator = new MaxindexIndicator { Period = 5 }; + indicator.Initialize(); + + var now = DateTime.UtcNow; + + for (int i = 0; i < 20; i++) + { + indicator.HistoricalData.AddBar( + now.AddMinutes(i), + 100 + (i * 2), + 105 + (i * 2), + 95 + (i * 2), + 102 + (i * 2)); + indicator.ProcessUpdate(new UpdateArgs(UpdateReason.HistoricalBar)); + } + + Assert.Equal(20, indicator.LinesSeries[0].Count); + + for (int i = 0; i < 20; i++) + { + Assert.True(double.IsFinite(indicator.LinesSeries[0].GetValue(i))); + } + } + + [Fact] + public void MaxindexIndicator_DifferentSourceTypes_Work() + { + var sources = new[] { SourceType.Open, SourceType.High, SourceType.Low, SourceType.Close, SourceType.HL2, SourceType.HLC3 }; + + foreach (var source in sources) + { + var indicator = new MaxindexIndicator { Period = 5, Source = source }; + indicator.Initialize(); + + var now = DateTime.UtcNow; + indicator.HistoricalData.AddBar(now, 100, 110, 90, 105); + indicator.ProcessUpdate(new UpdateArgs(UpdateReason.HistoricalBar)); + + Assert.True(double.IsFinite(indicator.LinesSeries[0].GetValue(0)), + $"Source {source} should produce finite value"); + } + } + + [Fact] + public void MaxindexIndicator_Period_CanBeChanged() + { + var indicator = new MaxindexIndicator { Period = 10 }; + Assert.Equal(10, indicator.Period); + + indicator.Period = 20; + Assert.Equal(20, indicator.Period); + } + + [Fact] + public void MaxindexIndicator_Uptrend_MaxAtCurrentBar() + { + // In a monotonic uptrend, the max is always the current bar (bars-ago = 0) + var indicator = new MaxindexIndicator { Period = 5 }; + indicator.Initialize(); + + var now = DateTime.UtcNow; + + for (int i = 0; i < 10; i++) + { + double price = 100 + (i * 5); + indicator.HistoricalData.AddBar(now.AddMinutes(i), price, price + 2, price - 2, price); + indicator.ProcessUpdate(new UpdateArgs(UpdateReason.HistoricalBar)); + } + + double lastIndex = indicator.LinesSeries[0].GetValue(0); + Assert.Equal(0, lastIndex); // Max is at current bar → bars-ago = 0 + } + + [Fact] + public void MaxindexIndicator_Downtrend_MaxAtOldestBar() + { + // In a monotonic downtrend, the max is the oldest bar (bars-ago = period-1) + var indicator = new MaxindexIndicator { Period = 5 }; + indicator.Initialize(); + + var now = DateTime.UtcNow; + + for (int i = 0; i < 10; i++) + { + double price = 200 - (i * 5); + indicator.HistoricalData.AddBar(now.AddMinutes(i), price, price + 2, price - 2, price); + indicator.ProcessUpdate(new UpdateArgs(UpdateReason.HistoricalBar)); + } + + double lastIndex = indicator.LinesSeries[0].GetValue(0); + Assert.Equal(4, lastIndex); // Max is at oldest bar → bars-ago = period-1 = 4 + } + + [Fact] + public void MaxindexIndicator_ShowColdValues_False_SetsNaN() + { + var indicator = new MaxindexIndicator { Period = 10, ShowColdValues = false }; + indicator.Initialize(); + + var now = DateTime.UtcNow; + indicator.HistoricalData.AddBar(now, 100, 105, 95, 102); + indicator.ProcessUpdate(new UpdateArgs(UpdateReason.HistoricalBar)); + + Assert.True(double.IsNaN(indicator.LinesSeries[0].GetValue(0))); + } + + [Fact] + public void MaxindexIndicator_DifferentPeriods_Work() + { + var periods = new[] { 2, 5, 10, 20 }; + + foreach (var period in periods) + { + var indicator = new MaxindexIndicator { Period = period }; + indicator.Initialize(); + + var now = DateTime.UtcNow; + + for (int i = 0; i < period + 5; i++) + { + indicator.HistoricalData.AddBar(now.AddMinutes(i), 100 + i, 102 + i, 98 + i, 101 + i); + indicator.ProcessUpdate(new UpdateArgs(UpdateReason.HistoricalBar)); + } + + Assert.Equal(period + 5, indicator.LinesSeries[0].Count); + } + } +} diff --git a/lib/numerics/minindex/Minindex.Quantower.cs b/lib/numerics/minindex/Minindex.Quantower.cs new file mode 100644 index 00000000..67219632 --- /dev/null +++ b/lib/numerics/minindex/Minindex.Quantower.cs @@ -0,0 +1,59 @@ +using System.Drawing; +using System.Runtime.CompilerServices; +using TradingPlatform.BusinessLayer; + +namespace QuanTAlib; + +/// +/// MININDEX (Rolling Minimum Index) Quantower indicator. +/// Returns the bars-ago position of the minimum value within a rolling window. +/// +[SkipLocalsInit] +public class MinindexIndicator : Indicator, IWatchlistIndicator +{ + [InputParameter("Period", sortIndex: 1, 2, 1000, 1, 0)] + public int Period { get; set; } = 14; + + [IndicatorExtensions.DataSourceInput] + public SourceType Source { get; set; } = SourceType.Close; + + [InputParameter("Show cold values", sortIndex: 21)] + public bool ShowColdValues { get; set; } = true; + + private Minindex _indicator = null!; + protected LineSeries Series; + protected string SourceName = null!; + private Func _priceSelector = null!; + + public int MinHistoryDepths => Period; + int IWatchlistIndicator.MinHistoryDepths => MinHistoryDepths; + + public override string ShortName => $"MININDEX({Period})"; + + public MinindexIndicator() + { + OnBackGround = false; + SeparateWindow = true; + SourceName = Source.ToString(); + Name = "MININDEX - Rolling Minimum Index"; + Description = "Returns the bars-ago position of the minimum value within a rolling lookback window."; + Series = new LineSeries(name: "MININDEX", color: IndicatorExtensions.Momentum, width: 2, style: LineStyle.Histogramm); + AddLineSeries(Series); + } + + protected override void OnInit() + { + _indicator = new Minindex(Period); + SourceName = Source.ToString(); + _priceSelector = Source.GetPriceSelector(); + base.OnInit(); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + protected override void OnUpdate(UpdateArgs args) + { + var item = HistoricalData[Count - 1, SeekOriginHistory.Begin]; + TValue result = _indicator.Update(new TValue(item.TimeLeft.Ticks, _priceSelector(item)), isNew: args.IsNewBar()); + Series.SetValue(result.Value, _indicator.IsHot, ShowColdValues); + } +} diff --git a/lib/numerics/minindex/tests/Minindex.Quantower.Tests.cs b/lib/numerics/minindex/tests/Minindex.Quantower.Tests.cs new file mode 100644 index 00000000..f0f618a3 --- /dev/null +++ b/lib/numerics/minindex/tests/Minindex.Quantower.Tests.cs @@ -0,0 +1,223 @@ +using TradingPlatform.BusinessLayer; + +namespace QuanTAlib.Tests; + +public class MinindexIndicatorTests +{ + [Fact] + public void MinindexIndicator_Constructor_SetsDefaults() + { + var indicator = new MinindexIndicator(); + + Assert.Equal(14, indicator.Period); + Assert.Equal(SourceType.Close, indicator.Source); + Assert.True(indicator.ShowColdValues); + Assert.Equal("MININDEX - Rolling Minimum Index", indicator.Name); + Assert.True(indicator.SeparateWindow); + Assert.False(indicator.OnBackGround); + } + + [Fact] + public void MinindexIndicator_MinHistoryDepths_EqualsPeriod() + { + var indicator = new MinindexIndicator { Period = 20 }; + + Assert.Equal(20, indicator.MinHistoryDepths); + Assert.Equal(20, ((IWatchlistIndicator)indicator).MinHistoryDepths); + } + + [Fact] + public void MinindexIndicator_ShortName_IncludesPeriod() + { + var indicator = new MinindexIndicator { Period = 10 }; + + Assert.Equal("MININDEX(10)", indicator.ShortName); + } + + [Fact] + public void MinindexIndicator_Initialize_CreatesLineSeries() + { + var indicator = new MinindexIndicator { Period = 5 }; + indicator.Initialize(); + + Assert.Single(indicator.LinesSeries); + } + + [Fact] + public void MinindexIndicator_ProcessUpdate_HistoricalBar_ComputesValue() + { + var indicator = new MinindexIndicator { Period = 5 }; + indicator.Initialize(); + + var now = DateTime.UtcNow; + indicator.HistoricalData.AddBar(now, 100, 105, 95, 102); + + var args = new UpdateArgs(UpdateReason.HistoricalBar); + indicator.ProcessUpdate(args); + + Assert.Equal(1, indicator.LinesSeries[0].Count); + Assert.True(double.IsFinite(indicator.LinesSeries[0].GetValue(0))); + } + + [Fact] + public void MinindexIndicator_ProcessUpdate_NewBar_ComputesValue() + { + var indicator = new MinindexIndicator { Period = 5 }; + indicator.Initialize(); + + var now = DateTime.UtcNow; + indicator.HistoricalData.AddBar(now, 100, 105, 95, 102); + indicator.HistoricalData.AddBar(now.AddMinutes(1), 102, 108, 100, 106); + + indicator.ProcessUpdate(new UpdateArgs(UpdateReason.HistoricalBar)); + indicator.ProcessUpdate(new UpdateArgs(UpdateReason.NewBar)); + + Assert.Equal(2, indicator.LinesSeries[0].Count); + } + + [Fact] + public void MinindexIndicator_ProcessUpdate_NewTick_ProcessesWithoutError() + { + var indicator = new MinindexIndicator { Period = 5 }; + indicator.Initialize(); + + var now = DateTime.UtcNow; + indicator.HistoricalData.AddBar(now, 100, 105, 95, 102); + + indicator.ProcessUpdate(new UpdateArgs(UpdateReason.HistoricalBar)); + indicator.ProcessUpdate(new UpdateArgs(UpdateReason.NewTick)); + + Assert.Equal(2, indicator.LinesSeries[0].Count); + } + + [Fact] + public void MinindexIndicator_MultipleUpdates_ProducesCorrectSequence() + { + var indicator = new MinindexIndicator { Period = 5 }; + indicator.Initialize(); + + var now = DateTime.UtcNow; + + for (int i = 0; i < 20; i++) + { + indicator.HistoricalData.AddBar( + now.AddMinutes(i), + 100 + (i * 2), + 105 + (i * 2), + 95 + (i * 2), + 102 + (i * 2)); + indicator.ProcessUpdate(new UpdateArgs(UpdateReason.HistoricalBar)); + } + + Assert.Equal(20, indicator.LinesSeries[0].Count); + + for (int i = 0; i < 20; i++) + { + Assert.True(double.IsFinite(indicator.LinesSeries[0].GetValue(i))); + } + } + + [Fact] + public void MinindexIndicator_DifferentSourceTypes_Work() + { + var sources = new[] { SourceType.Open, SourceType.High, SourceType.Low, SourceType.Close, SourceType.HL2, SourceType.HLC3 }; + + foreach (var source in sources) + { + var indicator = new MinindexIndicator { Period = 5, Source = source }; + indicator.Initialize(); + + var now = DateTime.UtcNow; + indicator.HistoricalData.AddBar(now, 100, 110, 90, 105); + indicator.ProcessUpdate(new UpdateArgs(UpdateReason.HistoricalBar)); + + Assert.True(double.IsFinite(indicator.LinesSeries[0].GetValue(0)), + $"Source {source} should produce finite value"); + } + } + + [Fact] + public void MinindexIndicator_Period_CanBeChanged() + { + var indicator = new MinindexIndicator { Period = 10 }; + Assert.Equal(10, indicator.Period); + + indicator.Period = 20; + Assert.Equal(20, indicator.Period); + } + + [Fact] + public void MinindexIndicator_Downtrend_MinAtCurrentBar() + { + // In a monotonic downtrend, the min is always the current bar (bars-ago = 0) + var indicator = new MinindexIndicator { Period = 5 }; + indicator.Initialize(); + + var now = DateTime.UtcNow; + + for (int i = 0; i < 10; i++) + { + double price = 200 - (i * 5); + indicator.HistoricalData.AddBar(now.AddMinutes(i), price, price + 2, price - 2, price); + indicator.ProcessUpdate(new UpdateArgs(UpdateReason.HistoricalBar)); + } + + double lastIndex = indicator.LinesSeries[0].GetValue(0); + Assert.Equal(0, lastIndex); // Min is at current bar → bars-ago = 0 + } + + [Fact] + public void MinindexIndicator_Uptrend_MinAtOldestBar() + { + // In a monotonic uptrend, the min is the oldest bar (bars-ago = period-1) + var indicator = new MinindexIndicator { Period = 5 }; + indicator.Initialize(); + + var now = DateTime.UtcNow; + + for (int i = 0; i < 10; i++) + { + double price = 100 + (i * 5); + indicator.HistoricalData.AddBar(now.AddMinutes(i), price, price + 2, price - 2, price); + indicator.ProcessUpdate(new UpdateArgs(UpdateReason.HistoricalBar)); + } + + double lastIndex = indicator.LinesSeries[0].GetValue(0); + Assert.Equal(4, lastIndex); // Min is at oldest bar → bars-ago = period-1 = 4 + } + + [Fact] + public void MinindexIndicator_ShowColdValues_False_SetsNaN() + { + var indicator = new MinindexIndicator { Period = 10, ShowColdValues = false }; + indicator.Initialize(); + + var now = DateTime.UtcNow; + indicator.HistoricalData.AddBar(now, 100, 105, 95, 102); + indicator.ProcessUpdate(new UpdateArgs(UpdateReason.HistoricalBar)); + + Assert.True(double.IsNaN(indicator.LinesSeries[0].GetValue(0))); + } + + [Fact] + public void MinindexIndicator_DifferentPeriods_Work() + { + var periods = new[] { 2, 5, 10, 20 }; + + foreach (var period in periods) + { + var indicator = new MinindexIndicator { Period = period }; + indicator.Initialize(); + + var now = DateTime.UtcNow; + + for (int i = 0; i < period + 5; i++) + { + indicator.HistoricalData.AddBar(now.AddMinutes(i), 100 + i, 102 + i, 98 + i, 101 + i); + indicator.ProcessUpdate(new UpdateArgs(UpdateReason.HistoricalBar)); + } + + Assert.Equal(period + 5, indicator.LinesSeries[0].Count); + } + } +} diff --git a/lib/numerics/normalize/Normalize.Tests.cs b/lib/numerics/normalize/tests/Normalize.Tests.cs similarity index 100% rename from lib/numerics/normalize/Normalize.Tests.cs rename to lib/numerics/normalize/tests/Normalize.Tests.cs diff --git a/lib/numerics/normalize/Normalize.Validation.Tests.cs b/lib/numerics/normalize/tests/Normalize.Validation.Tests.cs similarity index 100% rename from lib/numerics/normalize/Normalize.Validation.Tests.cs rename to lib/numerics/normalize/tests/Normalize.Validation.Tests.cs diff --git a/lib/numerics/normdist/Normdist.Tests.cs b/lib/numerics/normdist/tests/Normdist.Tests.cs similarity index 100% rename from lib/numerics/normdist/Normdist.Tests.cs rename to lib/numerics/normdist/tests/Normdist.Tests.cs diff --git a/lib/numerics/normdist/Normdist.Validation.Tests.cs b/lib/numerics/normdist/tests/Normdist.Validation.Tests.cs similarity index 100% rename from lib/numerics/normdist/Normdist.Validation.Tests.cs rename to lib/numerics/normdist/tests/Normdist.Validation.Tests.cs diff --git a/lib/numerics/poissondist/Poissondist.Tests.cs b/lib/numerics/poissondist/tests/Poissondist.Tests.cs similarity index 100% rename from lib/numerics/poissondist/Poissondist.Tests.cs rename to lib/numerics/poissondist/tests/Poissondist.Tests.cs diff --git a/lib/numerics/poissondist/Poissondist.Validation.Tests.cs b/lib/numerics/poissondist/tests/Poissondist.Validation.Tests.cs similarity index 100% rename from lib/numerics/poissondist/Poissondist.Validation.Tests.cs rename to lib/numerics/poissondist/tests/Poissondist.Validation.Tests.cs diff --git a/lib/numerics/relu/Relu.Tests.cs b/lib/numerics/relu/tests/Relu.Tests.cs similarity index 100% rename from lib/numerics/relu/Relu.Tests.cs rename to lib/numerics/relu/tests/Relu.Tests.cs diff --git a/lib/numerics/relu/Relu.Validation.Tests.cs b/lib/numerics/relu/tests/Relu.Validation.Tests.cs similarity index 100% rename from lib/numerics/relu/Relu.Validation.Tests.cs rename to lib/numerics/relu/tests/Relu.Validation.Tests.cs diff --git a/lib/numerics/sigmoid/Sigmoid.Tests.cs b/lib/numerics/sigmoid/tests/Sigmoid.Tests.cs similarity index 100% rename from lib/numerics/sigmoid/Sigmoid.Tests.cs rename to lib/numerics/sigmoid/tests/Sigmoid.Tests.cs diff --git a/lib/numerics/sigmoid/Sigmoid.Validation.Tests.cs b/lib/numerics/sigmoid/tests/Sigmoid.Validation.Tests.cs similarity index 100% rename from lib/numerics/sigmoid/Sigmoid.Validation.Tests.cs rename to lib/numerics/sigmoid/tests/Sigmoid.Validation.Tests.cs diff --git a/lib/numerics/slope/Slope.Tests.cs b/lib/numerics/slope/tests/Slope.Tests.cs similarity index 100% rename from lib/numerics/slope/Slope.Tests.cs rename to lib/numerics/slope/tests/Slope.Tests.cs diff --git a/lib/numerics/slope/Slope.Validation.Tests.cs b/lib/numerics/slope/tests/Slope.Validation.Tests.cs similarity index 100% rename from lib/numerics/slope/Slope.Validation.Tests.cs rename to lib/numerics/slope/tests/Slope.Validation.Tests.cs diff --git a/lib/numerics/sqrttrans/Sqrttrans.Tests.cs b/lib/numerics/sqrttrans/tests/Sqrttrans.Tests.cs similarity index 100% rename from lib/numerics/sqrttrans/Sqrttrans.Tests.cs rename to lib/numerics/sqrttrans/tests/Sqrttrans.Tests.cs diff --git a/lib/numerics/sqrttrans/Sqrttrans.Validation.Tests.cs b/lib/numerics/sqrttrans/tests/Sqrttrans.Validation.Tests.cs similarity index 100% rename from lib/numerics/sqrttrans/Sqrttrans.Validation.Tests.cs rename to lib/numerics/sqrttrans/tests/Sqrttrans.Validation.Tests.cs diff --git a/lib/numerics/tdist/Tdist.Tests.cs b/lib/numerics/tdist/tests/Tdist.Tests.cs similarity index 100% rename from lib/numerics/tdist/Tdist.Tests.cs rename to lib/numerics/tdist/tests/Tdist.Tests.cs diff --git a/lib/numerics/tdist/Tdist.Validation.Tests.cs b/lib/numerics/tdist/tests/Tdist.Validation.Tests.cs similarity index 100% rename from lib/numerics/tdist/Tdist.Validation.Tests.cs rename to lib/numerics/tdist/tests/Tdist.Validation.Tests.cs diff --git a/lib/numerics/weibulldist/Weibulldist.Tests.cs b/lib/numerics/weibulldist/tests/Weibulldist.Tests.cs similarity index 100% rename from lib/numerics/weibulldist/Weibulldist.Tests.cs rename to lib/numerics/weibulldist/tests/Weibulldist.Tests.cs diff --git a/lib/numerics/weibulldist/Weibulldist.Validation.Tests.cs b/lib/numerics/weibulldist/tests/Weibulldist.Validation.Tests.cs similarity index 100% rename from lib/numerics/weibulldist/Weibulldist.Validation.Tests.cs rename to lib/numerics/weibulldist/tests/Weibulldist.Validation.Tests.cs diff --git a/lib/oscillators/ac/Ac.Quantower.Tests.cs b/lib/oscillators/ac/tests/Ac.Quantower.Tests.cs similarity index 100% rename from lib/oscillators/ac/Ac.Quantower.Tests.cs rename to lib/oscillators/ac/tests/Ac.Quantower.Tests.cs diff --git a/lib/oscillators/ac/Ac.Tests.cs b/lib/oscillators/ac/tests/Ac.Tests.cs similarity index 100% rename from lib/oscillators/ac/Ac.Tests.cs rename to lib/oscillators/ac/tests/Ac.Tests.cs diff --git a/lib/oscillators/ac/Ac.Validation.Tests.cs b/lib/oscillators/ac/tests/Ac.Validation.Tests.cs similarity index 100% rename from lib/oscillators/ac/Ac.Validation.Tests.cs rename to lib/oscillators/ac/tests/Ac.Validation.Tests.cs diff --git a/lib/oscillators/ao/Ao.Quantower.Tests.cs b/lib/oscillators/ao/tests/Ao.Quantower.Tests.cs similarity index 100% rename from lib/oscillators/ao/Ao.Quantower.Tests.cs rename to lib/oscillators/ao/tests/Ao.Quantower.Tests.cs diff --git a/lib/oscillators/ao/Ao.Tests.cs b/lib/oscillators/ao/tests/Ao.Tests.cs similarity index 100% rename from lib/oscillators/ao/Ao.Tests.cs rename to lib/oscillators/ao/tests/Ao.Tests.cs diff --git a/lib/oscillators/ao/Ao.Validation.Tests.cs b/lib/oscillators/ao/tests/Ao.Validation.Tests.cs similarity index 100% rename from lib/oscillators/ao/Ao.Validation.Tests.cs rename to lib/oscillators/ao/tests/Ao.Validation.Tests.cs diff --git a/lib/oscillators/apo/Apo.Quantower.Tests.cs b/lib/oscillators/apo/tests/Apo.Quantower.Tests.cs similarity index 100% rename from lib/oscillators/apo/Apo.Quantower.Tests.cs rename to lib/oscillators/apo/tests/Apo.Quantower.Tests.cs diff --git a/lib/oscillators/apo/Apo.Tests.cs b/lib/oscillators/apo/tests/Apo.Tests.cs similarity index 100% rename from lib/oscillators/apo/Apo.Tests.cs rename to lib/oscillators/apo/tests/Apo.Tests.cs diff --git a/lib/oscillators/apo/Apo.Validation.Tests.cs b/lib/oscillators/apo/tests/Apo.Validation.Tests.cs similarity index 100% rename from lib/oscillators/apo/Apo.Validation.Tests.cs rename to lib/oscillators/apo/tests/Apo.Validation.Tests.cs diff --git a/lib/oscillators/bbb/Bbb.Quantower.Tests.cs b/lib/oscillators/bbb/tests/Bbb.Quantower.Tests.cs similarity index 100% rename from lib/oscillators/bbb/Bbb.Quantower.Tests.cs rename to lib/oscillators/bbb/tests/Bbb.Quantower.Tests.cs diff --git a/lib/oscillators/bbb/Bbb.Tests.cs b/lib/oscillators/bbb/tests/Bbb.Tests.cs similarity index 100% rename from lib/oscillators/bbb/Bbb.Tests.cs rename to lib/oscillators/bbb/tests/Bbb.Tests.cs diff --git a/lib/oscillators/bbb/Bbb.Validation.Tests.cs b/lib/oscillators/bbb/tests/Bbb.Validation.Tests.cs similarity index 100% rename from lib/oscillators/bbb/Bbb.Validation.Tests.cs rename to lib/oscillators/bbb/tests/Bbb.Validation.Tests.cs diff --git a/lib/oscillators/bbi/Bbi.Quantower.Tests.cs b/lib/oscillators/bbi/tests/Bbi.Quantower.Tests.cs similarity index 100% rename from lib/oscillators/bbi/Bbi.Quantower.Tests.cs rename to lib/oscillators/bbi/tests/Bbi.Quantower.Tests.cs diff --git a/lib/oscillators/bbi/Bbi.Tests.cs b/lib/oscillators/bbi/tests/Bbi.Tests.cs similarity index 100% rename from lib/oscillators/bbi/Bbi.Tests.cs rename to lib/oscillators/bbi/tests/Bbi.Tests.cs diff --git a/lib/oscillators/bbi/Bbi.Validation.Tests.cs b/lib/oscillators/bbi/tests/Bbi.Validation.Tests.cs similarity index 100% rename from lib/oscillators/bbi/Bbi.Validation.Tests.cs rename to lib/oscillators/bbi/tests/Bbi.Validation.Tests.cs diff --git a/lib/oscillators/bbs/Bbs.Quantower.Tests.cs b/lib/oscillators/bbs/tests/Bbs.Quantower.Tests.cs similarity index 100% rename from lib/oscillators/bbs/Bbs.Quantower.Tests.cs rename to lib/oscillators/bbs/tests/Bbs.Quantower.Tests.cs diff --git a/lib/oscillators/bbs/Bbs.Tests.cs b/lib/oscillators/bbs/tests/Bbs.Tests.cs similarity index 100% rename from lib/oscillators/bbs/Bbs.Tests.cs rename to lib/oscillators/bbs/tests/Bbs.Tests.cs diff --git a/lib/oscillators/bbs/Bbs.Validation.Tests.cs b/lib/oscillators/bbs/tests/Bbs.Validation.Tests.cs similarity index 100% rename from lib/oscillators/bbs/Bbs.Validation.Tests.cs rename to lib/oscillators/bbs/tests/Bbs.Validation.Tests.cs diff --git a/lib/oscillators/brar/Brar.Quantower.Tests.cs b/lib/oscillators/brar/tests/Brar.Quantower.Tests.cs similarity index 100% rename from lib/oscillators/brar/Brar.Quantower.Tests.cs rename to lib/oscillators/brar/tests/Brar.Quantower.Tests.cs diff --git a/lib/oscillators/brar/Brar.Tests.cs b/lib/oscillators/brar/tests/Brar.Tests.cs similarity index 100% rename from lib/oscillators/brar/Brar.Tests.cs rename to lib/oscillators/brar/tests/Brar.Tests.cs diff --git a/lib/oscillators/brar/Brar.Validation.Tests.cs b/lib/oscillators/brar/tests/Brar.Validation.Tests.cs similarity index 100% rename from lib/oscillators/brar/Brar.Validation.Tests.cs rename to lib/oscillators/brar/tests/Brar.Validation.Tests.cs diff --git a/lib/oscillators/cfo/Cfo.Quantower.Tests.cs b/lib/oscillators/cfo/tests/Cfo.Quantower.Tests.cs similarity index 100% rename from lib/oscillators/cfo/Cfo.Quantower.Tests.cs rename to lib/oscillators/cfo/tests/Cfo.Quantower.Tests.cs diff --git a/lib/oscillators/cfo/Cfo.Tests.cs b/lib/oscillators/cfo/tests/Cfo.Tests.cs similarity index 100% rename from lib/oscillators/cfo/Cfo.Tests.cs rename to lib/oscillators/cfo/tests/Cfo.Tests.cs diff --git a/lib/oscillators/cfo/Cfo.Validation.Tests.cs b/lib/oscillators/cfo/tests/Cfo.Validation.Tests.cs similarity index 100% rename from lib/oscillators/cfo/Cfo.Validation.Tests.cs rename to lib/oscillators/cfo/tests/Cfo.Validation.Tests.cs diff --git a/lib/oscillators/coppock/Coppock.Quantower.Tests.cs b/lib/oscillators/coppock/tests/Coppock.Quantower.Tests.cs similarity index 100% rename from lib/oscillators/coppock/Coppock.Quantower.Tests.cs rename to lib/oscillators/coppock/tests/Coppock.Quantower.Tests.cs diff --git a/lib/oscillators/coppock/Coppock.Tests.cs b/lib/oscillators/coppock/tests/Coppock.Tests.cs similarity index 100% rename from lib/oscillators/coppock/Coppock.Tests.cs rename to lib/oscillators/coppock/tests/Coppock.Tests.cs diff --git a/lib/oscillators/coppock/Coppock.Validation.Tests.cs b/lib/oscillators/coppock/tests/Coppock.Validation.Tests.cs similarity index 100% rename from lib/oscillators/coppock/Coppock.Validation.Tests.cs rename to lib/oscillators/coppock/tests/Coppock.Validation.Tests.cs diff --git a/lib/oscillators/crsi/Crsi.Quantower.Tests.cs b/lib/oscillators/crsi/tests/Crsi.Quantower.Tests.cs similarity index 100% rename from lib/oscillators/crsi/Crsi.Quantower.Tests.cs rename to lib/oscillators/crsi/tests/Crsi.Quantower.Tests.cs diff --git a/lib/oscillators/crsi/Crsi.Tests.cs b/lib/oscillators/crsi/tests/Crsi.Tests.cs similarity index 100% rename from lib/oscillators/crsi/Crsi.Tests.cs rename to lib/oscillators/crsi/tests/Crsi.Tests.cs diff --git a/lib/oscillators/crsi/Crsi.Validation.Tests.cs b/lib/oscillators/crsi/tests/Crsi.Validation.Tests.cs similarity index 100% rename from lib/oscillators/crsi/Crsi.Validation.Tests.cs rename to lib/oscillators/crsi/tests/Crsi.Validation.Tests.cs diff --git a/lib/oscillators/cti/Cti.Quantower.Tests.cs b/lib/oscillators/cti/tests/Cti.Quantower.Tests.cs similarity index 100% rename from lib/oscillators/cti/Cti.Quantower.Tests.cs rename to lib/oscillators/cti/tests/Cti.Quantower.Tests.cs diff --git a/lib/oscillators/cti/Cti.Tests.cs b/lib/oscillators/cti/tests/Cti.Tests.cs similarity index 100% rename from lib/oscillators/cti/Cti.Tests.cs rename to lib/oscillators/cti/tests/Cti.Tests.cs diff --git a/lib/oscillators/cti/Cti.Validation.Tests.cs b/lib/oscillators/cti/tests/Cti.Validation.Tests.cs similarity index 100% rename from lib/oscillators/cti/Cti.Validation.Tests.cs rename to lib/oscillators/cti/tests/Cti.Validation.Tests.cs diff --git a/lib/oscillators/deco/Deco.Quantower.Tests.cs b/lib/oscillators/deco/tests/Deco.Quantower.Tests.cs similarity index 100% rename from lib/oscillators/deco/Deco.Quantower.Tests.cs rename to lib/oscillators/deco/tests/Deco.Quantower.Tests.cs diff --git a/lib/oscillators/deco/Deco.Tests.cs b/lib/oscillators/deco/tests/Deco.Tests.cs similarity index 100% rename from lib/oscillators/deco/Deco.Tests.cs rename to lib/oscillators/deco/tests/Deco.Tests.cs diff --git a/lib/oscillators/deco/Deco.Validation.Tests.cs b/lib/oscillators/deco/tests/Deco.Validation.Tests.cs similarity index 100% rename from lib/oscillators/deco/Deco.Validation.Tests.cs rename to lib/oscillators/deco/tests/Deco.Validation.Tests.cs diff --git a/lib/oscillators/dem/Dem.Quantower.Tests.cs b/lib/oscillators/dem/tests/Dem.Quantower.Tests.cs similarity index 100% rename from lib/oscillators/dem/Dem.Quantower.Tests.cs rename to lib/oscillators/dem/tests/Dem.Quantower.Tests.cs diff --git a/lib/oscillators/dem/Dem.Tests.cs b/lib/oscillators/dem/tests/Dem.Tests.cs similarity index 100% rename from lib/oscillators/dem/Dem.Tests.cs rename to lib/oscillators/dem/tests/Dem.Tests.cs diff --git a/lib/oscillators/dem/Dem.Validation.Tests.cs b/lib/oscillators/dem/tests/Dem.Validation.Tests.cs similarity index 100% rename from lib/oscillators/dem/Dem.Validation.Tests.cs rename to lib/oscillators/dem/tests/Dem.Validation.Tests.cs diff --git a/lib/oscillators/dosc/Dosc.Quantower.Tests.cs b/lib/oscillators/dosc/tests/Dosc.Quantower.Tests.cs similarity index 100% rename from lib/oscillators/dosc/Dosc.Quantower.Tests.cs rename to lib/oscillators/dosc/tests/Dosc.Quantower.Tests.cs diff --git a/lib/oscillators/dosc/Dosc.Tests.cs b/lib/oscillators/dosc/tests/Dosc.Tests.cs similarity index 100% rename from lib/oscillators/dosc/Dosc.Tests.cs rename to lib/oscillators/dosc/tests/Dosc.Tests.cs diff --git a/lib/oscillators/dosc/Dosc.Validation.Tests.cs b/lib/oscillators/dosc/tests/Dosc.Validation.Tests.cs similarity index 100% rename from lib/oscillators/dosc/Dosc.Validation.Tests.cs rename to lib/oscillators/dosc/tests/Dosc.Validation.Tests.cs diff --git a/lib/oscillators/dpo/Dpo.Quantower.Tests.cs b/lib/oscillators/dpo/tests/Dpo.Quantower.Tests.cs similarity index 100% rename from lib/oscillators/dpo/Dpo.Quantower.Tests.cs rename to lib/oscillators/dpo/tests/Dpo.Quantower.Tests.cs diff --git a/lib/oscillators/dpo/Dpo.Tests.cs b/lib/oscillators/dpo/tests/Dpo.Tests.cs similarity index 100% rename from lib/oscillators/dpo/Dpo.Tests.cs rename to lib/oscillators/dpo/tests/Dpo.Tests.cs diff --git a/lib/oscillators/dpo/Dpo.Validation.Tests.cs b/lib/oscillators/dpo/tests/Dpo.Validation.Tests.cs similarity index 100% rename from lib/oscillators/dpo/Dpo.Validation.Tests.cs rename to lib/oscillators/dpo/tests/Dpo.Validation.Tests.cs diff --git a/lib/oscillators/dymoi/Dymoi.Quantower.Tests.cs b/lib/oscillators/dymoi/tests/Dymoi.Quantower.Tests.cs similarity index 100% rename from lib/oscillators/dymoi/Dymoi.Quantower.Tests.cs rename to lib/oscillators/dymoi/tests/Dymoi.Quantower.Tests.cs diff --git a/lib/oscillators/dymoi/Dymoi.Tests.cs b/lib/oscillators/dymoi/tests/Dymoi.Tests.cs similarity index 100% rename from lib/oscillators/dymoi/Dymoi.Tests.cs rename to lib/oscillators/dymoi/tests/Dymoi.Tests.cs diff --git a/lib/oscillators/dymoi/Dymoi.Validation.Tests.cs b/lib/oscillators/dymoi/tests/Dymoi.Validation.Tests.cs similarity index 100% rename from lib/oscillators/dymoi/Dymoi.Validation.Tests.cs rename to lib/oscillators/dymoi/tests/Dymoi.Validation.Tests.cs diff --git a/lib/oscillators/er/Er.Quantower.Tests.cs b/lib/oscillators/er/tests/Er.Quantower.Tests.cs similarity index 100% rename from lib/oscillators/er/Er.Quantower.Tests.cs rename to lib/oscillators/er/tests/Er.Quantower.Tests.cs diff --git a/lib/oscillators/er/Er.Tests.cs b/lib/oscillators/er/tests/Er.Tests.cs similarity index 100% rename from lib/oscillators/er/Er.Tests.cs rename to lib/oscillators/er/tests/Er.Tests.cs diff --git a/lib/oscillators/er/Er.Validation.Tests.cs b/lib/oscillators/er/tests/Er.Validation.Tests.cs similarity index 100% rename from lib/oscillators/er/Er.Validation.Tests.cs rename to lib/oscillators/er/tests/Er.Validation.Tests.cs diff --git a/lib/oscillators/eri/Eri.Quantower.Tests.cs b/lib/oscillators/eri/tests/Eri.Quantower.Tests.cs similarity index 100% rename from lib/oscillators/eri/Eri.Quantower.Tests.cs rename to lib/oscillators/eri/tests/Eri.Quantower.Tests.cs diff --git a/lib/oscillators/eri/Eri.Tests.cs b/lib/oscillators/eri/tests/Eri.Tests.cs similarity index 100% rename from lib/oscillators/eri/Eri.Tests.cs rename to lib/oscillators/eri/tests/Eri.Tests.cs diff --git a/lib/oscillators/eri/Eri.Validation.Tests.cs b/lib/oscillators/eri/tests/Eri.Validation.Tests.cs similarity index 100% rename from lib/oscillators/eri/Eri.Validation.Tests.cs rename to lib/oscillators/eri/tests/Eri.Validation.Tests.cs diff --git a/lib/oscillators/fi/Fi.Quantower.Tests.cs b/lib/oscillators/fi/tests/Fi.Quantower.Tests.cs similarity index 100% rename from lib/oscillators/fi/Fi.Quantower.Tests.cs rename to lib/oscillators/fi/tests/Fi.Quantower.Tests.cs diff --git a/lib/oscillators/fi/Fi.Tests.cs b/lib/oscillators/fi/tests/Fi.Tests.cs similarity index 100% rename from lib/oscillators/fi/Fi.Tests.cs rename to lib/oscillators/fi/tests/Fi.Tests.cs diff --git a/lib/oscillators/fi/Fi.Validation.Tests.cs b/lib/oscillators/fi/tests/Fi.Validation.Tests.cs similarity index 100% rename from lib/oscillators/fi/Fi.Validation.Tests.cs rename to lib/oscillators/fi/tests/Fi.Validation.Tests.cs diff --git a/lib/oscillators/fisher/Fisher.Quantower.Tests.cs b/lib/oscillators/fisher/tests/Fisher.Quantower.Tests.cs similarity index 100% rename from lib/oscillators/fisher/Fisher.Quantower.Tests.cs rename to lib/oscillators/fisher/tests/Fisher.Quantower.Tests.cs diff --git a/lib/oscillators/fisher/Fisher.Tests.cs b/lib/oscillators/fisher/tests/Fisher.Tests.cs similarity index 100% rename from lib/oscillators/fisher/Fisher.Tests.cs rename to lib/oscillators/fisher/tests/Fisher.Tests.cs diff --git a/lib/oscillators/fisher/Fisher.Validation.Tests.cs b/lib/oscillators/fisher/tests/Fisher.Validation.Tests.cs similarity index 100% rename from lib/oscillators/fisher/Fisher.Validation.Tests.cs rename to lib/oscillators/fisher/tests/Fisher.Validation.Tests.cs diff --git a/lib/oscillators/fisher04/Fisher04.Quantower.Tests.cs b/lib/oscillators/fisher04/tests/Fisher04.Quantower.Tests.cs similarity index 100% rename from lib/oscillators/fisher04/Fisher04.Quantower.Tests.cs rename to lib/oscillators/fisher04/tests/Fisher04.Quantower.Tests.cs diff --git a/lib/oscillators/fisher04/Fisher04.Tests.cs b/lib/oscillators/fisher04/tests/Fisher04.Tests.cs similarity index 100% rename from lib/oscillators/fisher04/Fisher04.Tests.cs rename to lib/oscillators/fisher04/tests/Fisher04.Tests.cs diff --git a/lib/oscillators/fisher04/Fisher04.Validation.Tests.cs b/lib/oscillators/fisher04/tests/Fisher04.Validation.Tests.cs similarity index 100% rename from lib/oscillators/fisher04/Fisher04.Validation.Tests.cs rename to lib/oscillators/fisher04/tests/Fisher04.Validation.Tests.cs diff --git a/lib/oscillators/gator/Gator.Quantower.Tests.cs b/lib/oscillators/gator/tests/Gator.Quantower.Tests.cs similarity index 100% rename from lib/oscillators/gator/Gator.Quantower.Tests.cs rename to lib/oscillators/gator/tests/Gator.Quantower.Tests.cs diff --git a/lib/oscillators/gator/Gator.Tests.cs b/lib/oscillators/gator/tests/Gator.Tests.cs similarity index 100% rename from lib/oscillators/gator/Gator.Tests.cs rename to lib/oscillators/gator/tests/Gator.Tests.cs diff --git a/lib/oscillators/gator/Gator.Validation.Tests.cs b/lib/oscillators/gator/tests/Gator.Validation.Tests.cs similarity index 100% rename from lib/oscillators/gator/Gator.Validation.Tests.cs rename to lib/oscillators/gator/tests/Gator.Validation.Tests.cs diff --git a/lib/oscillators/imi/Imi.Quantower.Tests.cs b/lib/oscillators/imi/tests/Imi.Quantower.Tests.cs similarity index 100% rename from lib/oscillators/imi/Imi.Quantower.Tests.cs rename to lib/oscillators/imi/tests/Imi.Quantower.Tests.cs diff --git a/lib/oscillators/imi/Imi.Tests.cs b/lib/oscillators/imi/tests/Imi.Tests.cs similarity index 100% rename from lib/oscillators/imi/Imi.Tests.cs rename to lib/oscillators/imi/tests/Imi.Tests.cs diff --git a/lib/oscillators/imi/Imi.Validation.Tests.cs b/lib/oscillators/imi/tests/Imi.Validation.Tests.cs similarity index 100% rename from lib/oscillators/imi/Imi.Validation.Tests.cs rename to lib/oscillators/imi/tests/Imi.Validation.Tests.cs diff --git a/lib/oscillators/inertia/Inertia.Quantower.Tests.cs b/lib/oscillators/inertia/tests/Inertia.Quantower.Tests.cs similarity index 100% rename from lib/oscillators/inertia/Inertia.Quantower.Tests.cs rename to lib/oscillators/inertia/tests/Inertia.Quantower.Tests.cs diff --git a/lib/oscillators/inertia/Inertia.Tests.cs b/lib/oscillators/inertia/tests/Inertia.Tests.cs similarity index 100% rename from lib/oscillators/inertia/Inertia.Tests.cs rename to lib/oscillators/inertia/tests/Inertia.Tests.cs diff --git a/lib/oscillators/inertia/Inertia.Validation.Tests.cs b/lib/oscillators/inertia/tests/Inertia.Validation.Tests.cs similarity index 100% rename from lib/oscillators/inertia/Inertia.Validation.Tests.cs rename to lib/oscillators/inertia/tests/Inertia.Validation.Tests.cs diff --git a/lib/oscillators/kdj/Kdj.Quantower.Tests.cs b/lib/oscillators/kdj/tests/Kdj.Quantower.Tests.cs similarity index 100% rename from lib/oscillators/kdj/Kdj.Quantower.Tests.cs rename to lib/oscillators/kdj/tests/Kdj.Quantower.Tests.cs diff --git a/lib/oscillators/kdj/Kdj.Tests.cs b/lib/oscillators/kdj/tests/Kdj.Tests.cs similarity index 100% rename from lib/oscillators/kdj/Kdj.Tests.cs rename to lib/oscillators/kdj/tests/Kdj.Tests.cs diff --git a/lib/oscillators/kdj/Kdj.Validation.Tests.cs b/lib/oscillators/kdj/tests/Kdj.Validation.Tests.cs similarity index 100% rename from lib/oscillators/kdj/Kdj.Validation.Tests.cs rename to lib/oscillators/kdj/tests/Kdj.Validation.Tests.cs diff --git a/lib/oscillators/kri/Kri.Quantower.Tests.cs b/lib/oscillators/kri/tests/Kri.Quantower.Tests.cs similarity index 100% rename from lib/oscillators/kri/Kri.Quantower.Tests.cs rename to lib/oscillators/kri/tests/Kri.Quantower.Tests.cs diff --git a/lib/oscillators/kri/Kri.Tests.cs b/lib/oscillators/kri/tests/Kri.Tests.cs similarity index 100% rename from lib/oscillators/kri/Kri.Tests.cs rename to lib/oscillators/kri/tests/Kri.Tests.cs diff --git a/lib/oscillators/kri/Kri.Validation.Tests.cs b/lib/oscillators/kri/tests/Kri.Validation.Tests.cs similarity index 100% rename from lib/oscillators/kri/Kri.Validation.Tests.cs rename to lib/oscillators/kri/tests/Kri.Validation.Tests.cs diff --git a/lib/oscillators/kst/Kst.Quantower.Tests.cs b/lib/oscillators/kst/tests/Kst.Quantower.Tests.cs similarity index 100% rename from lib/oscillators/kst/Kst.Quantower.Tests.cs rename to lib/oscillators/kst/tests/Kst.Quantower.Tests.cs diff --git a/lib/oscillators/kst/Kst.Tests.cs b/lib/oscillators/kst/tests/Kst.Tests.cs similarity index 100% rename from lib/oscillators/kst/Kst.Tests.cs rename to lib/oscillators/kst/tests/Kst.Tests.cs diff --git a/lib/oscillators/kst/Kst.Validation.Tests.cs b/lib/oscillators/kst/tests/Kst.Validation.Tests.cs similarity index 100% rename from lib/oscillators/kst/Kst.Validation.Tests.cs rename to lib/oscillators/kst/tests/Kst.Validation.Tests.cs diff --git a/lib/oscillators/lrsi/Lrsi.Quantower.Tests.cs b/lib/oscillators/lrsi/tests/Lrsi.Quantower.Tests.cs similarity index 100% rename from lib/oscillators/lrsi/Lrsi.Quantower.Tests.cs rename to lib/oscillators/lrsi/tests/Lrsi.Quantower.Tests.cs diff --git a/lib/oscillators/lrsi/Lrsi.Tests.cs b/lib/oscillators/lrsi/tests/Lrsi.Tests.cs similarity index 100% rename from lib/oscillators/lrsi/Lrsi.Tests.cs rename to lib/oscillators/lrsi/tests/Lrsi.Tests.cs diff --git a/lib/oscillators/lrsi/Lrsi.Validation.Tests.cs b/lib/oscillators/lrsi/tests/Lrsi.Validation.Tests.cs similarity index 100% rename from lib/oscillators/lrsi/Lrsi.Validation.Tests.cs rename to lib/oscillators/lrsi/tests/Lrsi.Validation.Tests.cs diff --git a/lib/oscillators/marketfi/Marketfi.Quantower.Tests.cs b/lib/oscillators/marketfi/tests/Marketfi.Quantower.Tests.cs similarity index 100% rename from lib/oscillators/marketfi/Marketfi.Quantower.Tests.cs rename to lib/oscillators/marketfi/tests/Marketfi.Quantower.Tests.cs diff --git a/lib/oscillators/marketfi/Marketfi.Tests.cs b/lib/oscillators/marketfi/tests/Marketfi.Tests.cs similarity index 100% rename from lib/oscillators/marketfi/Marketfi.Tests.cs rename to lib/oscillators/marketfi/tests/Marketfi.Tests.cs diff --git a/lib/oscillators/marketfi/Marketfi.Validation.Tests.cs b/lib/oscillators/marketfi/tests/Marketfi.Validation.Tests.cs similarity index 100% rename from lib/oscillators/marketfi/Marketfi.Validation.Tests.cs rename to lib/oscillators/marketfi/tests/Marketfi.Validation.Tests.cs diff --git a/lib/oscillators/mstoch/Mstoch.Quantower.Tests.cs b/lib/oscillators/mstoch/tests/Mstoch.Quantower.Tests.cs similarity index 100% rename from lib/oscillators/mstoch/Mstoch.Quantower.Tests.cs rename to lib/oscillators/mstoch/tests/Mstoch.Quantower.Tests.cs diff --git a/lib/oscillators/mstoch/Mstoch.Tests.cs b/lib/oscillators/mstoch/tests/Mstoch.Tests.cs similarity index 100% rename from lib/oscillators/mstoch/Mstoch.Tests.cs rename to lib/oscillators/mstoch/tests/Mstoch.Tests.cs diff --git a/lib/oscillators/mstoch/Mstoch.Validation.Tests.cs b/lib/oscillators/mstoch/tests/Mstoch.Validation.Tests.cs similarity index 100% rename from lib/oscillators/mstoch/Mstoch.Validation.Tests.cs rename to lib/oscillators/mstoch/tests/Mstoch.Validation.Tests.cs diff --git a/lib/oscillators/pgo/Pgo.Quantower.Tests.cs b/lib/oscillators/pgo/tests/Pgo.Quantower.Tests.cs similarity index 100% rename from lib/oscillators/pgo/Pgo.Quantower.Tests.cs rename to lib/oscillators/pgo/tests/Pgo.Quantower.Tests.cs diff --git a/lib/oscillators/pgo/Pgo.Tests.cs b/lib/oscillators/pgo/tests/Pgo.Tests.cs similarity index 100% rename from lib/oscillators/pgo/Pgo.Tests.cs rename to lib/oscillators/pgo/tests/Pgo.Tests.cs diff --git a/lib/oscillators/pgo/Pgo.Validation.Tests.cs b/lib/oscillators/pgo/tests/Pgo.Validation.Tests.cs similarity index 100% rename from lib/oscillators/pgo/Pgo.Validation.Tests.cs rename to lib/oscillators/pgo/tests/Pgo.Validation.Tests.cs diff --git a/lib/oscillators/psl/Psl.Quantower.Tests.cs b/lib/oscillators/psl/tests/Psl.Quantower.Tests.cs similarity index 100% rename from lib/oscillators/psl/Psl.Quantower.Tests.cs rename to lib/oscillators/psl/tests/Psl.Quantower.Tests.cs diff --git a/lib/oscillators/psl/Psl.Tests.cs b/lib/oscillators/psl/tests/Psl.Tests.cs similarity index 100% rename from lib/oscillators/psl/Psl.Tests.cs rename to lib/oscillators/psl/tests/Psl.Tests.cs diff --git a/lib/oscillators/psl/Psl.Validation.Tests.cs b/lib/oscillators/psl/tests/Psl.Validation.Tests.cs similarity index 100% rename from lib/oscillators/psl/Psl.Validation.Tests.cs rename to lib/oscillators/psl/tests/Psl.Validation.Tests.cs diff --git a/lib/oscillators/qqe/Qqe.Quantower.Tests.cs b/lib/oscillators/qqe/tests/Qqe.Quantower.Tests.cs similarity index 100% rename from lib/oscillators/qqe/Qqe.Quantower.Tests.cs rename to lib/oscillators/qqe/tests/Qqe.Quantower.Tests.cs diff --git a/lib/oscillators/qqe/Qqe.Tests.cs b/lib/oscillators/qqe/tests/Qqe.Tests.cs similarity index 100% rename from lib/oscillators/qqe/Qqe.Tests.cs rename to lib/oscillators/qqe/tests/Qqe.Tests.cs diff --git a/lib/oscillators/qqe/Qqe.Validation.Tests.cs b/lib/oscillators/qqe/tests/Qqe.Validation.Tests.cs similarity index 100% rename from lib/oscillators/qqe/Qqe.Validation.Tests.cs rename to lib/oscillators/qqe/tests/Qqe.Validation.Tests.cs diff --git a/lib/oscillators/reflex/Reflex.Quantower.Tests.cs b/lib/oscillators/reflex/tests/Reflex.Quantower.Tests.cs similarity index 100% rename from lib/oscillators/reflex/Reflex.Quantower.Tests.cs rename to lib/oscillators/reflex/tests/Reflex.Quantower.Tests.cs diff --git a/lib/oscillators/reflex/Reflex.Tests.cs b/lib/oscillators/reflex/tests/Reflex.Tests.cs similarity index 100% rename from lib/oscillators/reflex/Reflex.Tests.cs rename to lib/oscillators/reflex/tests/Reflex.Tests.cs diff --git a/lib/oscillators/reflex/Reflex.Validation.Tests.cs b/lib/oscillators/reflex/tests/Reflex.Validation.Tests.cs similarity index 100% rename from lib/oscillators/reflex/Reflex.Validation.Tests.cs rename to lib/oscillators/reflex/tests/Reflex.Validation.Tests.cs diff --git a/lib/oscillators/reverseema/ReverseEma.Quantower.Tests.cs b/lib/oscillators/reverseema/tests/ReverseEma.Quantower.Tests.cs similarity index 100% rename from lib/oscillators/reverseema/ReverseEma.Quantower.Tests.cs rename to lib/oscillators/reverseema/tests/ReverseEma.Quantower.Tests.cs diff --git a/lib/oscillators/reverseema/ReverseEma.Tests.cs b/lib/oscillators/reverseema/tests/ReverseEma.Tests.cs similarity index 100% rename from lib/oscillators/reverseema/ReverseEma.Tests.cs rename to lib/oscillators/reverseema/tests/ReverseEma.Tests.cs diff --git a/lib/oscillators/reverseema/ReverseEma.Validation.Tests.cs b/lib/oscillators/reverseema/tests/ReverseEma.Validation.Tests.cs similarity index 100% rename from lib/oscillators/reverseema/ReverseEma.Validation.Tests.cs rename to lib/oscillators/reverseema/tests/ReverseEma.Validation.Tests.cs diff --git a/lib/oscillators/rvgi/Rvgi.Quantower.Tests.cs b/lib/oscillators/rvgi/tests/Rvgi.Quantower.Tests.cs similarity index 100% rename from lib/oscillators/rvgi/Rvgi.Quantower.Tests.cs rename to lib/oscillators/rvgi/tests/Rvgi.Quantower.Tests.cs diff --git a/lib/oscillators/rvgi/Rvgi.Tests.cs b/lib/oscillators/rvgi/tests/Rvgi.Tests.cs similarity index 100% rename from lib/oscillators/rvgi/Rvgi.Tests.cs rename to lib/oscillators/rvgi/tests/Rvgi.Tests.cs diff --git a/lib/oscillators/rvgi/Rvgi.Validation.Tests.cs b/lib/oscillators/rvgi/tests/Rvgi.Validation.Tests.cs similarity index 100% rename from lib/oscillators/rvgi/Rvgi.Validation.Tests.cs rename to lib/oscillators/rvgi/tests/Rvgi.Validation.Tests.cs diff --git a/lib/oscillators/smi/Smi.Quantower.Tests.cs b/lib/oscillators/smi/tests/Smi.Quantower.Tests.cs similarity index 100% rename from lib/oscillators/smi/Smi.Quantower.Tests.cs rename to lib/oscillators/smi/tests/Smi.Quantower.Tests.cs diff --git a/lib/oscillators/smi/Smi.Tests.cs b/lib/oscillators/smi/tests/Smi.Tests.cs similarity index 100% rename from lib/oscillators/smi/Smi.Tests.cs rename to lib/oscillators/smi/tests/Smi.Tests.cs diff --git a/lib/oscillators/smi/Smi.Validation.Tests.cs b/lib/oscillators/smi/tests/Smi.Validation.Tests.cs similarity index 100% rename from lib/oscillators/smi/Smi.Validation.Tests.cs rename to lib/oscillators/smi/tests/Smi.Validation.Tests.cs diff --git a/lib/oscillators/squeeze/Squeeze.Quantower.Tests.cs b/lib/oscillators/squeeze/tests/Squeeze.Quantower.Tests.cs similarity index 100% rename from lib/oscillators/squeeze/Squeeze.Quantower.Tests.cs rename to lib/oscillators/squeeze/tests/Squeeze.Quantower.Tests.cs diff --git a/lib/oscillators/squeeze/Squeeze.Tests.cs b/lib/oscillators/squeeze/tests/Squeeze.Tests.cs similarity index 100% rename from lib/oscillators/squeeze/Squeeze.Tests.cs rename to lib/oscillators/squeeze/tests/Squeeze.Tests.cs diff --git a/lib/oscillators/squeeze/Squeeze.Validation.Tests.cs b/lib/oscillators/squeeze/tests/Squeeze.Validation.Tests.cs similarity index 100% rename from lib/oscillators/squeeze/Squeeze.Validation.Tests.cs rename to lib/oscillators/squeeze/tests/Squeeze.Validation.Tests.cs diff --git a/lib/oscillators/stc/Stc.Quantower.Tests.cs b/lib/oscillators/stc/tests/Stc.Quantower.Tests.cs similarity index 100% rename from lib/oscillators/stc/Stc.Quantower.Tests.cs rename to lib/oscillators/stc/tests/Stc.Quantower.Tests.cs diff --git a/lib/oscillators/stc/Stc.Tests.cs b/lib/oscillators/stc/tests/Stc.Tests.cs similarity index 100% rename from lib/oscillators/stc/Stc.Tests.cs rename to lib/oscillators/stc/tests/Stc.Tests.cs diff --git a/lib/oscillators/stc/Stc.Validation.Tests.cs b/lib/oscillators/stc/tests/Stc.Validation.Tests.cs similarity index 100% rename from lib/oscillators/stc/Stc.Validation.Tests.cs rename to lib/oscillators/stc/tests/Stc.Validation.Tests.cs diff --git a/lib/oscillators/stoch/Stoch.Quantower.Tests.cs b/lib/oscillators/stoch/tests/Stoch.Quantower.Tests.cs similarity index 100% rename from lib/oscillators/stoch/Stoch.Quantower.Tests.cs rename to lib/oscillators/stoch/tests/Stoch.Quantower.Tests.cs diff --git a/lib/oscillators/stoch/Stoch.Tests.cs b/lib/oscillators/stoch/tests/Stoch.Tests.cs similarity index 100% rename from lib/oscillators/stoch/Stoch.Tests.cs rename to lib/oscillators/stoch/tests/Stoch.Tests.cs diff --git a/lib/oscillators/stoch/Stoch.Validation.Tests.cs b/lib/oscillators/stoch/tests/Stoch.Validation.Tests.cs similarity index 100% rename from lib/oscillators/stoch/Stoch.Validation.Tests.cs rename to lib/oscillators/stoch/tests/Stoch.Validation.Tests.cs diff --git a/lib/oscillators/stochf/Stochf.Quantower.Tests.cs b/lib/oscillators/stochf/tests/Stochf.Quantower.Tests.cs similarity index 100% rename from lib/oscillators/stochf/Stochf.Quantower.Tests.cs rename to lib/oscillators/stochf/tests/Stochf.Quantower.Tests.cs diff --git a/lib/oscillators/stochf/Stochf.Tests.cs b/lib/oscillators/stochf/tests/Stochf.Tests.cs similarity index 100% rename from lib/oscillators/stochf/Stochf.Tests.cs rename to lib/oscillators/stochf/tests/Stochf.Tests.cs diff --git a/lib/oscillators/stochf/Stochf.Validation.Tests.cs b/lib/oscillators/stochf/tests/Stochf.Validation.Tests.cs similarity index 100% rename from lib/oscillators/stochf/Stochf.Validation.Tests.cs rename to lib/oscillators/stochf/tests/Stochf.Validation.Tests.cs diff --git a/lib/oscillators/stochrsi/Stochrsi.Quantower.Tests.cs b/lib/oscillators/stochrsi/tests/Stochrsi.Quantower.Tests.cs similarity index 100% rename from lib/oscillators/stochrsi/Stochrsi.Quantower.Tests.cs rename to lib/oscillators/stochrsi/tests/Stochrsi.Quantower.Tests.cs diff --git a/lib/oscillators/stochrsi/Stochrsi.Tests.cs b/lib/oscillators/stochrsi/tests/Stochrsi.Tests.cs similarity index 100% rename from lib/oscillators/stochrsi/Stochrsi.Tests.cs rename to lib/oscillators/stochrsi/tests/Stochrsi.Tests.cs diff --git a/lib/oscillators/stochrsi/Stochrsi.Validation.Tests.cs b/lib/oscillators/stochrsi/tests/Stochrsi.Validation.Tests.cs similarity index 100% rename from lib/oscillators/stochrsi/Stochrsi.Validation.Tests.cs rename to lib/oscillators/stochrsi/tests/Stochrsi.Validation.Tests.cs diff --git a/lib/oscillators/td_seq/Td_seq.Quantower.Tests.cs b/lib/oscillators/td_seq/tests/Td_seq.Quantower.Tests.cs similarity index 100% rename from lib/oscillators/td_seq/Td_seq.Quantower.Tests.cs rename to lib/oscillators/td_seq/tests/Td_seq.Quantower.Tests.cs diff --git a/lib/oscillators/td_seq/Td_seq.Tests.cs b/lib/oscillators/td_seq/tests/Td_seq.Tests.cs similarity index 100% rename from lib/oscillators/td_seq/Td_seq.Tests.cs rename to lib/oscillators/td_seq/tests/Td_seq.Tests.cs diff --git a/lib/oscillators/td_seq/Td_seq.Validation.Tests.cs b/lib/oscillators/td_seq/tests/Td_seq.Validation.Tests.cs similarity index 100% rename from lib/oscillators/td_seq/Td_seq.Validation.Tests.cs rename to lib/oscillators/td_seq/tests/Td_seq.Validation.Tests.cs diff --git a/lib/oscillators/trendflex/Trendflex.Quantower.Tests.cs b/lib/oscillators/trendflex/tests/Trendflex.Quantower.Tests.cs similarity index 100% rename from lib/oscillators/trendflex/Trendflex.Quantower.Tests.cs rename to lib/oscillators/trendflex/tests/Trendflex.Quantower.Tests.cs diff --git a/lib/oscillators/trendflex/Trendflex.Tests.cs b/lib/oscillators/trendflex/tests/Trendflex.Tests.cs similarity index 100% rename from lib/oscillators/trendflex/Trendflex.Tests.cs rename to lib/oscillators/trendflex/tests/Trendflex.Tests.cs diff --git a/lib/oscillators/trendflex/Trendflex.Validation.Tests.cs b/lib/oscillators/trendflex/tests/Trendflex.Validation.Tests.cs similarity index 100% rename from lib/oscillators/trendflex/Trendflex.Validation.Tests.cs rename to lib/oscillators/trendflex/tests/Trendflex.Validation.Tests.cs diff --git a/lib/oscillators/trix/Trix.Quantower.Tests.cs b/lib/oscillators/trix/tests/Trix.Quantower.Tests.cs similarity index 100% rename from lib/oscillators/trix/Trix.Quantower.Tests.cs rename to lib/oscillators/trix/tests/Trix.Quantower.Tests.cs diff --git a/lib/oscillators/trix/Trix.Tests.cs b/lib/oscillators/trix/tests/Trix.Tests.cs similarity index 100% rename from lib/oscillators/trix/Trix.Tests.cs rename to lib/oscillators/trix/tests/Trix.Tests.cs diff --git a/lib/oscillators/trix/Trix.Validation.Tests.cs b/lib/oscillators/trix/tests/Trix.Validation.Tests.cs similarity index 100% rename from lib/oscillators/trix/Trix.Validation.Tests.cs rename to lib/oscillators/trix/tests/Trix.Validation.Tests.cs diff --git a/lib/oscillators/ttm_wave/TtmWave.Quantower.Tests.cs b/lib/oscillators/ttm_wave/tests/TtmWave.Quantower.Tests.cs similarity index 100% rename from lib/oscillators/ttm_wave/TtmWave.Quantower.Tests.cs rename to lib/oscillators/ttm_wave/tests/TtmWave.Quantower.Tests.cs diff --git a/lib/oscillators/ttm_wave/TtmWave.Tests.cs b/lib/oscillators/ttm_wave/tests/TtmWave.Tests.cs similarity index 100% rename from lib/oscillators/ttm_wave/TtmWave.Tests.cs rename to lib/oscillators/ttm_wave/tests/TtmWave.Tests.cs diff --git a/lib/oscillators/ttm_wave/TtmWave.Validation.Tests.cs b/lib/oscillators/ttm_wave/tests/TtmWave.Validation.Tests.cs similarity index 100% rename from lib/oscillators/ttm_wave/TtmWave.Validation.Tests.cs rename to lib/oscillators/ttm_wave/tests/TtmWave.Validation.Tests.cs diff --git a/lib/oscillators/ultosc/Ultosc.Quantower.Tests.cs b/lib/oscillators/ultosc/tests/Ultosc.Quantower.Tests.cs similarity index 100% rename from lib/oscillators/ultosc/Ultosc.Quantower.Tests.cs rename to lib/oscillators/ultosc/tests/Ultosc.Quantower.Tests.cs diff --git a/lib/oscillators/ultosc/Ultosc.Tests.cs b/lib/oscillators/ultosc/tests/Ultosc.Tests.cs similarity index 100% rename from lib/oscillators/ultosc/Ultosc.Tests.cs rename to lib/oscillators/ultosc/tests/Ultosc.Tests.cs diff --git a/lib/oscillators/ultosc/Ultosc.Validation.Tests.cs b/lib/oscillators/ultosc/tests/Ultosc.Validation.Tests.cs similarity index 100% rename from lib/oscillators/ultosc/Ultosc.Validation.Tests.cs rename to lib/oscillators/ultosc/tests/Ultosc.Validation.Tests.cs diff --git a/lib/oscillators/willr/Willr.Quantower.Tests.cs b/lib/oscillators/willr/tests/Willr.Quantower.Tests.cs similarity index 100% rename from lib/oscillators/willr/Willr.Quantower.Tests.cs rename to lib/oscillators/willr/tests/Willr.Quantower.Tests.cs diff --git a/lib/oscillators/willr/Willr.Tests.cs b/lib/oscillators/willr/tests/Willr.Tests.cs similarity index 100% rename from lib/oscillators/willr/Willr.Tests.cs rename to lib/oscillators/willr/tests/Willr.Tests.cs diff --git a/lib/oscillators/willr/Willr.Validation.Tests.cs b/lib/oscillators/willr/tests/Willr.Validation.Tests.cs similarity index 100% rename from lib/oscillators/willr/Willr.Validation.Tests.cs rename to lib/oscillators/willr/tests/Willr.Validation.Tests.cs diff --git a/lib/reversals/chandelier/Chandelier.Quantower.Tests.cs b/lib/reversals/chandelier/tests/Chandelier.Quantower.Tests.cs similarity index 100% rename from lib/reversals/chandelier/Chandelier.Quantower.Tests.cs rename to lib/reversals/chandelier/tests/Chandelier.Quantower.Tests.cs diff --git a/lib/reversals/chandelier/Chandelier.Tests.cs b/lib/reversals/chandelier/tests/Chandelier.Tests.cs similarity index 100% rename from lib/reversals/chandelier/Chandelier.Tests.cs rename to lib/reversals/chandelier/tests/Chandelier.Tests.cs diff --git a/lib/reversals/chandelier/Chandelier.Validation.Tests.cs b/lib/reversals/chandelier/tests/Chandelier.Validation.Tests.cs similarity index 100% rename from lib/reversals/chandelier/Chandelier.Validation.Tests.cs rename to lib/reversals/chandelier/tests/Chandelier.Validation.Tests.cs diff --git a/lib/reversals/ckstop/Ckstop.Quantower.Tests.cs b/lib/reversals/ckstop/tests/Ckstop.Quantower.Tests.cs similarity index 100% rename from lib/reversals/ckstop/Ckstop.Quantower.Tests.cs rename to lib/reversals/ckstop/tests/Ckstop.Quantower.Tests.cs diff --git a/lib/reversals/ckstop/Ckstop.Tests.cs b/lib/reversals/ckstop/tests/Ckstop.Tests.cs similarity index 100% rename from lib/reversals/ckstop/Ckstop.Tests.cs rename to lib/reversals/ckstop/tests/Ckstop.Tests.cs diff --git a/lib/reversals/ckstop/Ckstop.Validation.Tests.cs b/lib/reversals/ckstop/tests/Ckstop.Validation.Tests.cs similarity index 100% rename from lib/reversals/ckstop/Ckstop.Validation.Tests.cs rename to lib/reversals/ckstop/tests/Ckstop.Validation.Tests.cs diff --git a/lib/reversals/fractals/Fractals.Quantower.Tests.cs b/lib/reversals/fractals/tests/Fractals.Quantower.Tests.cs similarity index 100% rename from lib/reversals/fractals/Fractals.Quantower.Tests.cs rename to lib/reversals/fractals/tests/Fractals.Quantower.Tests.cs diff --git a/lib/reversals/fractals/Fractals.Tests.cs b/lib/reversals/fractals/tests/Fractals.Tests.cs similarity index 100% rename from lib/reversals/fractals/Fractals.Tests.cs rename to lib/reversals/fractals/tests/Fractals.Tests.cs diff --git a/lib/reversals/fractals/Fractals.Validation.Tests.cs b/lib/reversals/fractals/tests/Fractals.Validation.Tests.cs similarity index 100% rename from lib/reversals/fractals/Fractals.Validation.Tests.cs rename to lib/reversals/fractals/tests/Fractals.Validation.Tests.cs diff --git a/lib/reversals/pivot/Pivot.Quantower.Tests.cs b/lib/reversals/pivot/tests/Pivot.Quantower.Tests.cs similarity index 100% rename from lib/reversals/pivot/Pivot.Quantower.Tests.cs rename to lib/reversals/pivot/tests/Pivot.Quantower.Tests.cs diff --git a/lib/reversals/pivot/Pivot.Tests.cs b/lib/reversals/pivot/tests/Pivot.Tests.cs similarity index 100% rename from lib/reversals/pivot/Pivot.Tests.cs rename to lib/reversals/pivot/tests/Pivot.Tests.cs diff --git a/lib/reversals/pivot/Pivot.Validation.Tests.cs b/lib/reversals/pivot/tests/Pivot.Validation.Tests.cs similarity index 100% rename from lib/reversals/pivot/Pivot.Validation.Tests.cs rename to lib/reversals/pivot/tests/Pivot.Validation.Tests.cs diff --git a/lib/reversals/pivotcam/Pivotcam.Quantower.Tests.cs b/lib/reversals/pivotcam/tests/Pivotcam.Quantower.Tests.cs similarity index 100% rename from lib/reversals/pivotcam/Pivotcam.Quantower.Tests.cs rename to lib/reversals/pivotcam/tests/Pivotcam.Quantower.Tests.cs diff --git a/lib/reversals/pivotcam/Pivotcam.Tests.cs b/lib/reversals/pivotcam/tests/Pivotcam.Tests.cs similarity index 100% rename from lib/reversals/pivotcam/Pivotcam.Tests.cs rename to lib/reversals/pivotcam/tests/Pivotcam.Tests.cs diff --git a/lib/reversals/pivotcam/Pivotcam.Validation.Tests.cs b/lib/reversals/pivotcam/tests/Pivotcam.Validation.Tests.cs similarity index 100% rename from lib/reversals/pivotcam/Pivotcam.Validation.Tests.cs rename to lib/reversals/pivotcam/tests/Pivotcam.Validation.Tests.cs diff --git a/lib/reversals/pivotdem/Pivotdem.Quantower.Tests.cs b/lib/reversals/pivotdem/tests/Pivotdem.Quantower.Tests.cs similarity index 100% rename from lib/reversals/pivotdem/Pivotdem.Quantower.Tests.cs rename to lib/reversals/pivotdem/tests/Pivotdem.Quantower.Tests.cs diff --git a/lib/reversals/pivotdem/Pivotdem.Tests.cs b/lib/reversals/pivotdem/tests/Pivotdem.Tests.cs similarity index 100% rename from lib/reversals/pivotdem/Pivotdem.Tests.cs rename to lib/reversals/pivotdem/tests/Pivotdem.Tests.cs diff --git a/lib/reversals/pivotdem/Pivotdem.Validation.Tests.cs b/lib/reversals/pivotdem/tests/Pivotdem.Validation.Tests.cs similarity index 100% rename from lib/reversals/pivotdem/Pivotdem.Validation.Tests.cs rename to lib/reversals/pivotdem/tests/Pivotdem.Validation.Tests.cs diff --git a/lib/reversals/pivotext/Pivotext.Quantower.Tests.cs b/lib/reversals/pivotext/tests/Pivotext.Quantower.Tests.cs similarity index 100% rename from lib/reversals/pivotext/Pivotext.Quantower.Tests.cs rename to lib/reversals/pivotext/tests/Pivotext.Quantower.Tests.cs diff --git a/lib/reversals/pivotext/Pivotext.Tests.cs b/lib/reversals/pivotext/tests/Pivotext.Tests.cs similarity index 100% rename from lib/reversals/pivotext/Pivotext.Tests.cs rename to lib/reversals/pivotext/tests/Pivotext.Tests.cs diff --git a/lib/reversals/pivotext/Pivotext.Validation.Tests.cs b/lib/reversals/pivotext/tests/Pivotext.Validation.Tests.cs similarity index 100% rename from lib/reversals/pivotext/Pivotext.Validation.Tests.cs rename to lib/reversals/pivotext/tests/Pivotext.Validation.Tests.cs diff --git a/lib/reversals/pivotfib/Pivotfib.Quantower.Tests.cs b/lib/reversals/pivotfib/tests/Pivotfib.Quantower.Tests.cs similarity index 100% rename from lib/reversals/pivotfib/Pivotfib.Quantower.Tests.cs rename to lib/reversals/pivotfib/tests/Pivotfib.Quantower.Tests.cs diff --git a/lib/reversals/pivotfib/Pivotfib.Tests.cs b/lib/reversals/pivotfib/tests/Pivotfib.Tests.cs similarity index 100% rename from lib/reversals/pivotfib/Pivotfib.Tests.cs rename to lib/reversals/pivotfib/tests/Pivotfib.Tests.cs diff --git a/lib/reversals/pivotfib/Pivotfib.Validation.Tests.cs b/lib/reversals/pivotfib/tests/Pivotfib.Validation.Tests.cs similarity index 100% rename from lib/reversals/pivotfib/Pivotfib.Validation.Tests.cs rename to lib/reversals/pivotfib/tests/Pivotfib.Validation.Tests.cs diff --git a/lib/reversals/pivotwood/Pivotwood.Quantower.Tests.cs b/lib/reversals/pivotwood/tests/Pivotwood.Quantower.Tests.cs similarity index 100% rename from lib/reversals/pivotwood/Pivotwood.Quantower.Tests.cs rename to lib/reversals/pivotwood/tests/Pivotwood.Quantower.Tests.cs diff --git a/lib/reversals/pivotwood/Pivotwood.Tests.cs b/lib/reversals/pivotwood/tests/Pivotwood.Tests.cs similarity index 100% rename from lib/reversals/pivotwood/Pivotwood.Tests.cs rename to lib/reversals/pivotwood/tests/Pivotwood.Tests.cs diff --git a/lib/reversals/pivotwood/Pivotwood.Validation.Tests.cs b/lib/reversals/pivotwood/tests/Pivotwood.Validation.Tests.cs similarity index 100% rename from lib/reversals/pivotwood/Pivotwood.Validation.Tests.cs rename to lib/reversals/pivotwood/tests/Pivotwood.Validation.Tests.cs diff --git a/lib/reversals/psar/Psar.Quantower.Tests.cs b/lib/reversals/psar/tests/Psar.Quantower.Tests.cs similarity index 100% rename from lib/reversals/psar/Psar.Quantower.Tests.cs rename to lib/reversals/psar/tests/Psar.Quantower.Tests.cs diff --git a/lib/reversals/psar/Psar.Tests.cs b/lib/reversals/psar/tests/Psar.Tests.cs similarity index 100% rename from lib/reversals/psar/Psar.Tests.cs rename to lib/reversals/psar/tests/Psar.Tests.cs diff --git a/lib/reversals/psar/Psar.Validation.Tests.cs b/lib/reversals/psar/tests/Psar.Validation.Tests.cs similarity index 100% rename from lib/reversals/psar/Psar.Validation.Tests.cs rename to lib/reversals/psar/tests/Psar.Validation.Tests.cs diff --git a/lib/reversals/sarext/Sarext.Quantower.cs b/lib/reversals/sarext/Sarext.Quantower.cs new file mode 100644 index 00000000..3b5a5633 --- /dev/null +++ b/lib/reversals/sarext/Sarext.Quantower.cs @@ -0,0 +1,90 @@ +using System.Drawing; +using System.Runtime.CompilerServices; +using TradingPlatform.BusinessLayer; + +namespace QuanTAlib; + +/// +/// SAREXT (Parabolic SAR Extended) Quantower indicator. +/// Extended Parabolic SAR with asymmetric acceleration factors for long/short positions. +/// Sign-encoded output: positive = long, negative = short. +/// +[SkipLocalsInit] +public sealed class SarextIndicator : Indicator, IWatchlistIndicator +{ + [InputParameter("Start Value", sortIndex: 0, -1000.0, 1000.0, 0.01, 2)] + public double StartValue { get; set; } = 0; + + [InputParameter("Offset On Reverse", sortIndex: 1, 0.0, 100.0, 0.01, 2)] + public double OffsetOnReverse { get; set; } = 0; + + [InputParameter("AF Init Long", sortIndex: 2, 0.001, 1.0, 0.001, 3)] + public double AfInitLong { get; set; } = 0.02; + + [InputParameter("AF Long", sortIndex: 3, 0.001, 1.0, 0.001, 3)] + public double AfLong { get; set; } = 0.02; + + [InputParameter("AF Max Long", sortIndex: 4, 0.001, 1.0, 0.01, 2)] + public double AfMaxLong { get; set; } = 0.20; + + [InputParameter("AF Init Short", sortIndex: 5, 0.001, 1.0, 0.001, 3)] + public double AfInitShort { get; set; } = 0.02; + + [InputParameter("AF Short", sortIndex: 6, 0.001, 1.0, 0.001, 3)] + public double AfShort { get; set; } = 0.02; + + [InputParameter("AF Max Short", sortIndex: 7, 0.001, 1.0, 0.01, 2)] + public double AfMaxShort { get; set; } = 0.20; + + [InputParameter("Show cold values", sortIndex: 21)] + public bool ShowColdValues { get; set; } = true; + + private Sarext _indicator = null!; + private readonly LineSeries _sarSeries; + + public static int MinHistoryDepths => 2; + int IWatchlistIndicator.MinHistoryDepths => MinHistoryDepths; + + public override string ShortName => + $"SAREXT({AfInitLong:F2},{AfMaxLong:F2},{AfInitShort:F2},{AfMaxShort:F2})"; + + public override string SourceCodeLink => + "https://github.com/mihakralj/QuanTAlib/blob/main/lib/reversals/sarext/Sarext.cs"; + + public SarextIndicator() + { + OnBackGround = true; + SeparateWindow = false; + Name = "SAREXT - Parabolic SAR Extended"; + Description = "Extended Parabolic SAR with asymmetric acceleration factors for long and short positions. Sign-encoded output."; + + _sarSeries = new LineSeries(name: "SAREXT", color: Color.DodgerBlue, width: 2, style: LineStyle.Dot); + AddLineSeries(_sarSeries); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + protected override void OnInit() + { + _indicator = new Sarext(StartValue, OffsetOnReverse, + AfInitLong, AfLong, AfMaxLong, + AfInitShort, AfShort, AfMaxShort); + base.OnInit(); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + protected override void OnUpdate(UpdateArgs args) + { + _ = _indicator.Update(this.GetInputBar(args), args.IsNewBar()); + + double sarValue = _indicator.Last.Value; + double displayValue = Math.Abs(sarValue); + + _sarSeries.SetValue(displayValue, _indicator.IsHot, ShowColdValues); + + if (_indicator.IsHot || ShowColdValues) + { + Color color = _indicator.IsLong ? Color.Green : Color.Red; + _sarSeries.SetMarker(0, new IndicatorLineMarker(color)); + } + } +} diff --git a/lib/reversals/sarext/tests/Sarext.Quantower.Tests.cs b/lib/reversals/sarext/tests/Sarext.Quantower.Tests.cs new file mode 100644 index 00000000..ef454102 --- /dev/null +++ b/lib/reversals/sarext/tests/Sarext.Quantower.Tests.cs @@ -0,0 +1,229 @@ +using TradingPlatform.BusinessLayer; + +namespace QuanTAlib.Tests; + +public sealed class SarextIndicatorTests +{ + [Fact] + public void SarextIndicator_Constructor_SetsDefaults() + { + var indicator = new SarextIndicator(); + + Assert.Equal(0.0, indicator.StartValue); + Assert.Equal(0.0, indicator.OffsetOnReverse); + Assert.Equal(0.02, indicator.AfInitLong); + Assert.Equal(0.02, indicator.AfLong); + Assert.Equal(0.20, indicator.AfMaxLong); + Assert.Equal(0.02, indicator.AfInitShort); + Assert.Equal(0.02, indicator.AfShort); + Assert.Equal(0.20, indicator.AfMaxShort); + Assert.True(indicator.ShowColdValues); + Assert.Contains("SAREXT", indicator.Name, StringComparison.Ordinal); + Assert.False(indicator.SeparateWindow); + Assert.True(indicator.OnBackGround); + } + + [Fact] + public void SarextIndicator_MinHistoryDepths_EqualsTwo() + { + var indicator = new SarextIndicator(); + + Assert.Equal(2, SarextIndicator.MinHistoryDepths); + IWatchlistIndicator watchlistIndicator = indicator; + Assert.Equal(2, watchlistIndicator.MinHistoryDepths); + } + + [Fact] + public void SarextIndicator_ShortName_IncludesParameters() + { + var indicator = new SarextIndicator + { + AfInitLong = 0.02, + AfMaxLong = 0.20, + AfInitShort = 0.03, + AfMaxShort = 0.25 + }; + indicator.Initialize(); + + Assert.Contains("SAREXT", indicator.ShortName, StringComparison.Ordinal); + Assert.Contains("0.02", indicator.ShortName, StringComparison.Ordinal); + Assert.Contains("0.03", indicator.ShortName, StringComparison.Ordinal); + } + + [Fact] + public void SarextIndicator_SourceCodeLink_IsValid() + { + var indicator = new SarextIndicator(); + + Assert.Contains("github.com", indicator.SourceCodeLink, StringComparison.Ordinal); + Assert.Contains("Sarext", indicator.SourceCodeLink, StringComparison.Ordinal); + } + + [Fact] + public void SarextIndicator_Initialize_CreatesInternalIndicator() + { + var indicator = new SarextIndicator(); + + indicator.Initialize(); + + Assert.Single(indicator.LinesSeries); + } + + [Fact] + public void SarextIndicator_ProcessUpdate_HistoricalBar_ComputesValue() + { + var indicator = new SarextIndicator + { + AfInitLong = 0.02, + AfLong = 0.02, + AfMaxLong = 0.20, + AfInitShort = 0.02, + AfShort = 0.02, + AfMaxShort = 0.20 + }; + indicator.Initialize(); + + var now = DateTime.UtcNow; + for (int i = 0; i < 20; i++) + { + indicator.HistoricalData.AddBar(now.AddMinutes(i), 100 + i, 110 + i, 90 + i, 105 + i); + + var args = new UpdateArgs(UpdateReason.HistoricalBar); + indicator.ProcessUpdate(args); + } + + double sar = indicator.LinesSeries[0].GetValue(0); + + Assert.True(double.IsFinite(sar)); + } + + [Fact] + public void SarextIndicator_ProcessUpdate_NewBar_ComputesValue() + { + var indicator = new SarextIndicator + { + AfInitLong = 0.02, + AfLong = 0.02, + AfMaxLong = 0.20, + AfInitShort = 0.02, + AfShort = 0.02, + AfMaxShort = 0.20 + }; + indicator.Initialize(); + + var now = DateTime.UtcNow; + for (int i = 0; i < 10; i++) + { + indicator.HistoricalData.AddBar(now.AddMinutes(i), 100 + i, 110 + i, 90 + i, 105 + i); + var args = new UpdateArgs(UpdateReason.HistoricalBar); + indicator.ProcessUpdate(args); + } + + // Simulate a new bar + indicator.HistoricalData.AddBar(now.AddMinutes(10), 110, 120, 100, 115); + var newArgs = new UpdateArgs(UpdateReason.NewBar); + indicator.ProcessUpdate(newArgs); + + double sar = indicator.LinesSeries[0].GetValue(0); + + Assert.True(double.IsFinite(sar)); + } + + [Fact] + public void SarextIndicator_SingleLineSeries_IsPresent() + { + var indicator = new SarextIndicator(); + indicator.Initialize(); + + var now = DateTime.UtcNow; + for (int i = 0; i < 20; i++) + { + indicator.HistoricalData.AddBar(now.AddMinutes(i), 100 + i, 110 + i, 90 + i, 105 + i); + var args = new UpdateArgs(UpdateReason.HistoricalBar); + indicator.ProcessUpdate(args); + } + + Assert.Single(indicator.LinesSeries); + Assert.True(double.IsFinite(indicator.LinesSeries[0].GetValue(0))); + } + + [Fact] + public void SarextIndicator_Description_IsSet() + { + var indicator = new SarextIndicator(); + + Assert.NotNull(indicator.Description); + Assert.NotEmpty(indicator.Description); + Assert.Contains("SAR", indicator.Description, StringComparison.OrdinalIgnoreCase); + } + + [Fact] + public void SarextIndicator_OutputIsAbsoluteValue() + { + var indicator = new SarextIndicator(); + indicator.Initialize(); + + var now = DateTime.UtcNow; + for (int i = 0; i < 20; i++) + { + indicator.HistoricalData.AddBar(now.AddMinutes(i), 100 + i, 110 + i, 90 + i, 105 + i); + indicator.ProcessUpdate(new UpdateArgs(UpdateReason.HistoricalBar)); + } + + // Display value should always be positive (absolute value of sign-encoded SAR) + double displayValue = indicator.LinesSeries[0].GetValue(0); + Assert.True(displayValue >= 0, "Display value should be non-negative (absolute SAR)"); + } + + [Fact] + public void SarextIndicator_AsymmetricAf_ProducesFiniteValues() + { + var indicator = new SarextIndicator + { + AfInitLong = 0.01, + AfLong = 0.01, + AfMaxLong = 0.10, + AfInitShort = 0.03, + AfShort = 0.03, + AfMaxShort = 0.30 + }; + indicator.Initialize(); + + var now = DateTime.UtcNow; + for (int i = 0; i < 20; i++) + { + indicator.HistoricalData.AddBar(now.AddMinutes(i), 100 + i, 110 + i, 90 + i, 105 + i); + indicator.ProcessUpdate(new UpdateArgs(UpdateReason.HistoricalBar)); + } + + double sar = indicator.LinesSeries[0].GetValue(0); + Assert.True(double.IsFinite(sar)); + Assert.True(sar > 0, "SAR display value should be positive"); + } + + [Fact] + public void SarextIndicator_ShowColdValues_False_HidesColdValues() + { + var indicator = new SarextIndicator { ShowColdValues = false }; + indicator.Initialize(); + + var now = DateTime.UtcNow; + indicator.HistoricalData.AddBar(now, 100, 110, 90, 105); + indicator.ProcessUpdate(new UpdateArgs(UpdateReason.HistoricalBar)); + + // With ShowColdValues=false, cold values should be hidden + Assert.False(indicator.ShowColdValues); + } + + [Fact] + public void SarextIndicator_LineSeries_HasCorrectStyle() + { + var indicator = new SarextIndicator(); + indicator.Initialize(); + + var lineSeries = indicator.LinesSeries[0]; + + Assert.Equal(2, lineSeries.Width); + Assert.Equal(LineStyle.Dot, lineSeries.Style); + } +} diff --git a/lib/reversals/swings/Swings.Quantower.Tests.cs b/lib/reversals/swings/tests/Swings.Quantower.Tests.cs similarity index 100% rename from lib/reversals/swings/Swings.Quantower.Tests.cs rename to lib/reversals/swings/tests/Swings.Quantower.Tests.cs diff --git a/lib/reversals/swings/Swings.Tests.cs b/lib/reversals/swings/tests/Swings.Tests.cs similarity index 100% rename from lib/reversals/swings/Swings.Tests.cs rename to lib/reversals/swings/tests/Swings.Tests.cs diff --git a/lib/reversals/swings/Swings.Validation.Tests.cs b/lib/reversals/swings/tests/Swings.Validation.Tests.cs similarity index 100% rename from lib/reversals/swings/Swings.Validation.Tests.cs rename to lib/reversals/swings/tests/Swings.Validation.Tests.cs diff --git a/lib/reversals/ttm_scalper/TtmScalper.Quantower.Tests.cs b/lib/reversals/ttm_scalper/tests/TtmScalper.Quantower.Tests.cs similarity index 100% rename from lib/reversals/ttm_scalper/TtmScalper.Quantower.Tests.cs rename to lib/reversals/ttm_scalper/tests/TtmScalper.Quantower.Tests.cs diff --git a/lib/reversals/ttm_scalper/TtmScalper.Tests.cs b/lib/reversals/ttm_scalper/tests/TtmScalper.Tests.cs similarity index 100% rename from lib/reversals/ttm_scalper/TtmScalper.Tests.cs rename to lib/reversals/ttm_scalper/tests/TtmScalper.Tests.cs diff --git a/lib/reversals/ttm_scalper/TtmScalper.Validation.Tests.cs b/lib/reversals/ttm_scalper/tests/TtmScalper.Validation.Tests.cs similarity index 100% rename from lib/reversals/ttm_scalper/TtmScalper.Validation.Tests.cs rename to lib/reversals/ttm_scalper/tests/TtmScalper.Validation.Tests.cs diff --git a/lib/statistics/acf/Acf.Tests.cs b/lib/statistics/acf/tests/Acf.Tests.cs similarity index 100% rename from lib/statistics/acf/Acf.Tests.cs rename to lib/statistics/acf/tests/Acf.Tests.cs diff --git a/lib/statistics/acf/Acf.Validation.Tests.cs b/lib/statistics/acf/tests/Acf.Validation.Tests.cs similarity index 100% rename from lib/statistics/acf/Acf.Validation.Tests.cs rename to lib/statistics/acf/tests/Acf.Validation.Tests.cs diff --git a/lib/statistics/beta/Beta.Tests.cs b/lib/statistics/beta/tests/Beta.Tests.cs similarity index 100% rename from lib/statistics/beta/Beta.Tests.cs rename to lib/statistics/beta/tests/Beta.Tests.cs diff --git a/lib/statistics/beta/Beta.Validation.Tests.cs b/lib/statistics/beta/tests/Beta.Validation.Tests.cs similarity index 100% rename from lib/statistics/beta/Beta.Validation.Tests.cs rename to lib/statistics/beta/tests/Beta.Validation.Tests.cs diff --git a/lib/statistics/cma/Cma.Tests.cs b/lib/statistics/cma/tests/Cma.Tests.cs similarity index 100% rename from lib/statistics/cma/Cma.Tests.cs rename to lib/statistics/cma/tests/Cma.Tests.cs diff --git a/lib/statistics/cma/Cma.Validation.Tests.cs b/lib/statistics/cma/tests/Cma.Validation.Tests.cs similarity index 100% rename from lib/statistics/cma/Cma.Validation.Tests.cs rename to lib/statistics/cma/tests/Cma.Validation.Tests.cs diff --git a/lib/statistics/cointegration/Cointegration.Tests.cs b/lib/statistics/cointegration/tests/Cointegration.Tests.cs similarity index 100% rename from lib/statistics/cointegration/Cointegration.Tests.cs rename to lib/statistics/cointegration/tests/Cointegration.Tests.cs diff --git a/lib/statistics/cointegration/Cointegration.Validation.Tests.cs b/lib/statistics/cointegration/tests/Cointegration.Validation.Tests.cs similarity index 100% rename from lib/statistics/cointegration/Cointegration.Validation.Tests.cs rename to lib/statistics/cointegration/tests/Cointegration.Validation.Tests.cs diff --git a/lib/statistics/correlation/Correlation.Tests.cs b/lib/statistics/correlation/tests/Correlation.Tests.cs similarity index 100% rename from lib/statistics/correlation/Correlation.Tests.cs rename to lib/statistics/correlation/tests/Correlation.Tests.cs diff --git a/lib/statistics/correlation/Correlation.Validation.Tests.cs b/lib/statistics/correlation/tests/Correlation.Validation.Tests.cs similarity index 100% rename from lib/statistics/correlation/Correlation.Validation.Tests.cs rename to lib/statistics/correlation/tests/Correlation.Validation.Tests.cs diff --git a/lib/statistics/covariance/Covariance.Simd.Tests.cs b/lib/statistics/covariance/tests/Covariance.Simd.Tests.cs similarity index 100% rename from lib/statistics/covariance/Covariance.Simd.Tests.cs rename to lib/statistics/covariance/tests/Covariance.Simd.Tests.cs diff --git a/lib/statistics/covariance/Covariance.Tests.cs b/lib/statistics/covariance/tests/Covariance.Tests.cs similarity index 100% rename from lib/statistics/covariance/Covariance.Tests.cs rename to lib/statistics/covariance/tests/Covariance.Tests.cs diff --git a/lib/statistics/covariance/Covariance.Validation.Tests.cs b/lib/statistics/covariance/tests/Covariance.Validation.Tests.cs similarity index 100% rename from lib/statistics/covariance/Covariance.Validation.Tests.cs rename to lib/statistics/covariance/tests/Covariance.Validation.Tests.cs diff --git a/lib/statistics/entropy/Entropy.Tests.cs b/lib/statistics/entropy/tests/Entropy.Tests.cs similarity index 100% rename from lib/statistics/entropy/Entropy.Tests.cs rename to lib/statistics/entropy/tests/Entropy.Tests.cs diff --git a/lib/statistics/entropy/Entropy.Validation.Tests.cs b/lib/statistics/entropy/tests/Entropy.Validation.Tests.cs similarity index 100% rename from lib/statistics/entropy/Entropy.Validation.Tests.cs rename to lib/statistics/entropy/tests/Entropy.Validation.Tests.cs diff --git a/lib/statistics/geomean/Geomean.Tests.cs b/lib/statistics/geomean/tests/Geomean.Tests.cs similarity index 100% rename from lib/statistics/geomean/Geomean.Tests.cs rename to lib/statistics/geomean/tests/Geomean.Tests.cs diff --git a/lib/statistics/geomean/Geomean.Validation.Tests.cs b/lib/statistics/geomean/tests/Geomean.Validation.Tests.cs similarity index 100% rename from lib/statistics/geomean/Geomean.Validation.Tests.cs rename to lib/statistics/geomean/tests/Geomean.Validation.Tests.cs diff --git a/lib/statistics/granger/Granger.Tests.cs b/lib/statistics/granger/tests/Granger.Tests.cs similarity index 100% rename from lib/statistics/granger/Granger.Tests.cs rename to lib/statistics/granger/tests/Granger.Tests.cs diff --git a/lib/statistics/granger/Granger.Validation.Tests.cs b/lib/statistics/granger/tests/Granger.Validation.Tests.cs similarity index 100% rename from lib/statistics/granger/Granger.Validation.Tests.cs rename to lib/statistics/granger/tests/Granger.Validation.Tests.cs diff --git a/lib/statistics/harmean/Harmean.Tests.cs b/lib/statistics/harmean/tests/Harmean.Tests.cs similarity index 100% rename from lib/statistics/harmean/Harmean.Tests.cs rename to lib/statistics/harmean/tests/Harmean.Tests.cs diff --git a/lib/statistics/harmean/Harmean.Validation.Tests.cs b/lib/statistics/harmean/tests/Harmean.Validation.Tests.cs similarity index 100% rename from lib/statistics/harmean/Harmean.Validation.Tests.cs rename to lib/statistics/harmean/tests/Harmean.Validation.Tests.cs diff --git a/lib/statistics/hurst/Hurst.Tests.cs b/lib/statistics/hurst/tests/Hurst.Tests.cs similarity index 100% rename from lib/statistics/hurst/Hurst.Tests.cs rename to lib/statistics/hurst/tests/Hurst.Tests.cs diff --git a/lib/statistics/hurst/Hurst.Validation.Tests.cs b/lib/statistics/hurst/tests/Hurst.Validation.Tests.cs similarity index 100% rename from lib/statistics/hurst/Hurst.Validation.Tests.cs rename to lib/statistics/hurst/tests/Hurst.Validation.Tests.cs diff --git a/lib/statistics/iqr/Iqr.Tests.cs b/lib/statistics/iqr/tests/Iqr.Tests.cs similarity index 100% rename from lib/statistics/iqr/Iqr.Tests.cs rename to lib/statistics/iqr/tests/Iqr.Tests.cs diff --git a/lib/statistics/iqr/Iqr.Validation.Tests.cs b/lib/statistics/iqr/tests/Iqr.Validation.Tests.cs similarity index 100% rename from lib/statistics/iqr/Iqr.Validation.Tests.cs rename to lib/statistics/iqr/tests/Iqr.Validation.Tests.cs diff --git a/lib/statistics/jb/Jb.Tests.cs b/lib/statistics/jb/tests/Jb.Tests.cs similarity index 100% rename from lib/statistics/jb/Jb.Tests.cs rename to lib/statistics/jb/tests/Jb.Tests.cs diff --git a/lib/statistics/jb/Jb.Validation.Tests.cs b/lib/statistics/jb/tests/Jb.Validation.Tests.cs similarity index 100% rename from lib/statistics/jb/Jb.Validation.Tests.cs rename to lib/statistics/jb/tests/Jb.Validation.Tests.cs diff --git a/lib/statistics/kendall/Kendall.Tests.cs b/lib/statistics/kendall/tests/Kendall.Tests.cs similarity index 100% rename from lib/statistics/kendall/Kendall.Tests.cs rename to lib/statistics/kendall/tests/Kendall.Tests.cs diff --git a/lib/statistics/kendall/Kendall.Validation.Tests.cs b/lib/statistics/kendall/tests/Kendall.Validation.Tests.cs similarity index 100% rename from lib/statistics/kendall/Kendall.Validation.Tests.cs rename to lib/statistics/kendall/tests/Kendall.Validation.Tests.cs diff --git a/lib/statistics/kurtosis/Kurtosis.Tests.cs b/lib/statistics/kurtosis/tests/Kurtosis.Tests.cs similarity index 100% rename from lib/statistics/kurtosis/Kurtosis.Tests.cs rename to lib/statistics/kurtosis/tests/Kurtosis.Tests.cs diff --git a/lib/statistics/kurtosis/Kurtosis.Validation.Tests.cs b/lib/statistics/kurtosis/tests/Kurtosis.Validation.Tests.cs similarity index 100% rename from lib/statistics/kurtosis/Kurtosis.Validation.Tests.cs rename to lib/statistics/kurtosis/tests/Kurtosis.Validation.Tests.cs diff --git a/lib/statistics/linreg/LinReg.Tests.cs b/lib/statistics/linreg/tests/LinReg.Tests.cs similarity index 100% rename from lib/statistics/linreg/LinReg.Tests.cs rename to lib/statistics/linreg/tests/LinReg.Tests.cs diff --git a/lib/statistics/linreg/LinReg.Validation.Tests.cs b/lib/statistics/linreg/tests/LinReg.Validation.Tests.cs similarity index 100% rename from lib/statistics/linreg/LinReg.Validation.Tests.cs rename to lib/statistics/linreg/tests/LinReg.Validation.Tests.cs diff --git a/lib/statistics/meandev/MeanDev.Tests.cs b/lib/statistics/meandev/tests/MeanDev.Tests.cs similarity index 100% rename from lib/statistics/meandev/MeanDev.Tests.cs rename to lib/statistics/meandev/tests/MeanDev.Tests.cs diff --git a/lib/statistics/meandev/MeanDev.Validation.Tests.cs b/lib/statistics/meandev/tests/MeanDev.Validation.Tests.cs similarity index 100% rename from lib/statistics/meandev/MeanDev.Validation.Tests.cs rename to lib/statistics/meandev/tests/MeanDev.Validation.Tests.cs diff --git a/lib/statistics/median/Median.Tests.cs b/lib/statistics/median/tests/Median.Tests.cs similarity index 100% rename from lib/statistics/median/Median.Tests.cs rename to lib/statistics/median/tests/Median.Tests.cs diff --git a/lib/statistics/median/Median.Validation.Tests.cs b/lib/statistics/median/tests/Median.Validation.Tests.cs similarity index 100% rename from lib/statistics/median/Median.Validation.Tests.cs rename to lib/statistics/median/tests/Median.Validation.Tests.cs diff --git a/lib/statistics/mode/Mode.Tests.cs b/lib/statistics/mode/tests/Mode.Tests.cs similarity index 100% rename from lib/statistics/mode/Mode.Tests.cs rename to lib/statistics/mode/tests/Mode.Tests.cs diff --git a/lib/statistics/mode/Mode.Validation.Tests.cs b/lib/statistics/mode/tests/Mode.Validation.Tests.cs similarity index 100% rename from lib/statistics/mode/Mode.Validation.Tests.cs rename to lib/statistics/mode/tests/Mode.Validation.Tests.cs diff --git a/lib/statistics/pacf/Pacf.Tests.cs b/lib/statistics/pacf/tests/Pacf.Tests.cs similarity index 100% rename from lib/statistics/pacf/Pacf.Tests.cs rename to lib/statistics/pacf/tests/Pacf.Tests.cs diff --git a/lib/statistics/pacf/Pacf.Validation.Tests.cs b/lib/statistics/pacf/tests/Pacf.Validation.Tests.cs similarity index 100% rename from lib/statistics/pacf/Pacf.Validation.Tests.cs rename to lib/statistics/pacf/tests/Pacf.Validation.Tests.cs diff --git a/lib/statistics/percentile/Percentile.Tests.cs b/lib/statistics/percentile/tests/Percentile.Tests.cs similarity index 100% rename from lib/statistics/percentile/Percentile.Tests.cs rename to lib/statistics/percentile/tests/Percentile.Tests.cs diff --git a/lib/statistics/percentile/Percentile.Validation.Tests.cs b/lib/statistics/percentile/tests/Percentile.Validation.Tests.cs similarity index 100% rename from lib/statistics/percentile/Percentile.Validation.Tests.cs rename to lib/statistics/percentile/tests/Percentile.Validation.Tests.cs diff --git a/lib/statistics/polyfit/Polyfit.Tests.cs b/lib/statistics/polyfit/tests/Polyfit.Tests.cs similarity index 100% rename from lib/statistics/polyfit/Polyfit.Tests.cs rename to lib/statistics/polyfit/tests/Polyfit.Tests.cs diff --git a/lib/statistics/polyfit/Polyfit.Validation.Tests.cs b/lib/statistics/polyfit/tests/Polyfit.Validation.Tests.cs similarity index 100% rename from lib/statistics/polyfit/Polyfit.Validation.Tests.cs rename to lib/statistics/polyfit/tests/Polyfit.Validation.Tests.cs diff --git a/lib/statistics/quantile/Quantile.Tests.cs b/lib/statistics/quantile/tests/Quantile.Tests.cs similarity index 100% rename from lib/statistics/quantile/Quantile.Tests.cs rename to lib/statistics/quantile/tests/Quantile.Tests.cs diff --git a/lib/statistics/quantile/Quantile.Validation.Tests.cs b/lib/statistics/quantile/tests/Quantile.Validation.Tests.cs similarity index 100% rename from lib/statistics/quantile/Quantile.Validation.Tests.cs rename to lib/statistics/quantile/tests/Quantile.Validation.Tests.cs diff --git a/lib/statistics/skew/Skew.Tests.cs b/lib/statistics/skew/tests/Skew.Tests.cs similarity index 100% rename from lib/statistics/skew/Skew.Tests.cs rename to lib/statistics/skew/tests/Skew.Tests.cs diff --git a/lib/statistics/skew/Skew.Validation.Tests.cs b/lib/statistics/skew/tests/Skew.Validation.Tests.cs similarity index 100% rename from lib/statistics/skew/Skew.Validation.Tests.cs rename to lib/statistics/skew/tests/Skew.Validation.Tests.cs diff --git a/lib/statistics/spearman/Spearman.Tests.cs b/lib/statistics/spearman/tests/Spearman.Tests.cs similarity index 100% rename from lib/statistics/spearman/Spearman.Tests.cs rename to lib/statistics/spearman/tests/Spearman.Tests.cs diff --git a/lib/statistics/spearman/Spearman.Validation.Tests.cs b/lib/statistics/spearman/tests/Spearman.Validation.Tests.cs similarity index 100% rename from lib/statistics/spearman/Spearman.Validation.Tests.cs rename to lib/statistics/spearman/tests/Spearman.Validation.Tests.cs diff --git a/lib/statistics/stddev/StdDev.Tests.cs b/lib/statistics/stddev/tests/StdDev.Tests.cs similarity index 100% rename from lib/statistics/stddev/StdDev.Tests.cs rename to lib/statistics/stddev/tests/StdDev.Tests.cs diff --git a/lib/statistics/stddev/StdDev.Validation.Tests.cs b/lib/statistics/stddev/tests/StdDev.Validation.Tests.cs similarity index 100% rename from lib/statistics/stddev/StdDev.Validation.Tests.cs rename to lib/statistics/stddev/tests/StdDev.Validation.Tests.cs diff --git a/lib/statistics/stderr/Stderr.Tests.cs b/lib/statistics/stderr/tests/Stderr.Tests.cs similarity index 100% rename from lib/statistics/stderr/Stderr.Tests.cs rename to lib/statistics/stderr/tests/Stderr.Tests.cs diff --git a/lib/statistics/stderr/Stderr.Validation.Tests.cs b/lib/statistics/stderr/tests/Stderr.Validation.Tests.cs similarity index 100% rename from lib/statistics/stderr/Stderr.Validation.Tests.cs rename to lib/statistics/stderr/tests/Stderr.Validation.Tests.cs diff --git a/lib/statistics/sum/Sum.Tests.cs b/lib/statistics/sum/tests/Sum.Tests.cs similarity index 100% rename from lib/statistics/sum/Sum.Tests.cs rename to lib/statistics/sum/tests/Sum.Tests.cs diff --git a/lib/statistics/sum/Sum.Validation.Tests.cs b/lib/statistics/sum/tests/Sum.Validation.Tests.cs similarity index 100% rename from lib/statistics/sum/Sum.Validation.Tests.cs rename to lib/statistics/sum/tests/Sum.Validation.Tests.cs diff --git a/lib/statistics/theil/Theil.Tests.cs b/lib/statistics/theil/tests/Theil.Tests.cs similarity index 100% rename from lib/statistics/theil/Theil.Tests.cs rename to lib/statistics/theil/tests/Theil.Tests.cs diff --git a/lib/statistics/theil/Theil.Validation.Tests.cs b/lib/statistics/theil/tests/Theil.Validation.Tests.cs similarity index 100% rename from lib/statistics/theil/Theil.Validation.Tests.cs rename to lib/statistics/theil/tests/Theil.Validation.Tests.cs diff --git a/lib/statistics/trim/Trim.Tests.cs b/lib/statistics/trim/tests/Trim.Tests.cs similarity index 100% rename from lib/statistics/trim/Trim.Tests.cs rename to lib/statistics/trim/tests/Trim.Tests.cs diff --git a/lib/statistics/trim/Trim.Validation.Tests.cs b/lib/statistics/trim/tests/Trim.Validation.Tests.cs similarity index 100% rename from lib/statistics/trim/Trim.Validation.Tests.cs rename to lib/statistics/trim/tests/Trim.Validation.Tests.cs diff --git a/lib/statistics/variance/Variance.Quantower.cs b/lib/statistics/variance/Variance.Quantower.cs new file mode 100644 index 00000000..b77f2eed --- /dev/null +++ b/lib/statistics/variance/Variance.Quantower.cs @@ -0,0 +1,63 @@ +using System.Drawing; +using System.Runtime.CompilerServices; +using TradingPlatform.BusinessLayer; + +namespace QuanTAlib; + +/// +/// Variance Quantower indicator. +/// Measures the dispersion of data points around their mean over a rolling window. +/// +[SkipLocalsInit] +public class VarianceIndicator : Indicator, IWatchlistIndicator +{ + [InputParameter("Period", sortIndex: 1, 2, 1000, 1, 0)] + public int Period { get; set; } = 14; + + [InputParameter("Population", sortIndex: 2, variants: new object[] { + "Sample (N-1)", false, "Population (N)", true })] + public bool IsPopulation { get; set; } = false; + + [IndicatorExtensions.DataSourceInput] + public SourceType Source { get; set; } = SourceType.Close; + + [InputParameter("Show cold values", sortIndex: 21)] + public bool ShowColdValues { get; set; } = true; + + private Variance _indicator = null!; + protected LineSeries Series; + protected string SourceName = null!; + private Func _priceSelector = null!; + + public int MinHistoryDepths => Period; + int IWatchlistIndicator.MinHistoryDepths => MinHistoryDepths; + + public override string ShortName => $"VAR({Period},{(IsPopulation ? "Pop" : "Samp")})"; + + public VarianceIndicator() + { + OnBackGround = false; + SeparateWindow = true; + SourceName = Source.ToString(); + Name = "VAR - Variance"; + Description = "Measures the dispersion of a set of data points around their mean over a rolling window."; + Series = new LineSeries(name: "Variance", color: IndicatorExtensions.Averages, width: 2, style: LineStyle.Solid); + AddLineSeries(Series); + } + + protected override void OnInit() + { + _indicator = new Variance(Period, IsPopulation); + SourceName = Source.ToString(); + _priceSelector = Source.GetPriceSelector(); + base.OnInit(); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + protected override void OnUpdate(UpdateArgs args) + { + var item = HistoricalData[Count - 1, SeekOriginHistory.Begin]; + TValue result = _indicator.Update(new TValue(item.TimeLeft.Ticks, _priceSelector(item)), isNew: args.IsNewBar()); + Series.SetValue(result.Value, _indicator.IsHot, ShowColdValues); + } +} diff --git a/lib/statistics/variance/tests/Variance.Quantower.Tests.cs b/lib/statistics/variance/tests/Variance.Quantower.Tests.cs new file mode 100644 index 00000000..99186ef5 --- /dev/null +++ b/lib/statistics/variance/tests/Variance.Quantower.Tests.cs @@ -0,0 +1,303 @@ +using TradingPlatform.BusinessLayer; + +namespace QuanTAlib.Tests; + +public sealed class VarianceIndicatorTests +{ + [Fact] + public void VarianceIndicator_Constructor_SetsDefaults() + { + var indicator = new VarianceIndicator(); + + Assert.Equal(14, indicator.Period); + Assert.False(indicator.IsPopulation); + Assert.Equal(SourceType.Close, indicator.Source); + Assert.True(indicator.ShowColdValues); + Assert.Contains("VAR", indicator.Name, StringComparison.Ordinal); + Assert.True(indicator.SeparateWindow); + Assert.False(indicator.OnBackGround); + } + + [Fact] + public void VarianceIndicator_MinHistoryDepths_EqualsPeriod() + { + var indicator = new VarianceIndicator { Period = 20 }; + + Assert.Equal(20, indicator.MinHistoryDepths); + IWatchlistIndicator watchlistIndicator = indicator; + Assert.Equal(20, watchlistIndicator.MinHistoryDepths); + } + + [Fact] + public void VarianceIndicator_ShortName_IncludesParameters() + { + var indicator = new VarianceIndicator { Period = 20, IsPopulation = false }; + + Assert.Contains("VAR", indicator.ShortName, StringComparison.Ordinal); + Assert.Contains("20", indicator.ShortName, StringComparison.Ordinal); + Assert.Contains("Samp", indicator.ShortName, StringComparison.Ordinal); + } + + [Fact] + public void VarianceIndicator_ShortName_ShowsPopulation() + { + var indicator = new VarianceIndicator { Period = 14, IsPopulation = true }; + + Assert.Contains("Pop", indicator.ShortName, StringComparison.Ordinal); + } + + [Fact] + public void VarianceIndicator_Initialize_CreatesLineSeries() + { + var indicator = new VarianceIndicator { Period = 10 }; + + indicator.Initialize(); + + Assert.Single(indicator.LinesSeries); + } + + [Fact] + public void VarianceIndicator_ProcessUpdate_HistoricalBar_ComputesValue() + { + var indicator = new VarianceIndicator { Period = 5 }; + indicator.Initialize(); + + var now = DateTime.UtcNow; + indicator.HistoricalData.AddBar(now, 100, 105, 95, 102); + + var args = new UpdateArgs(UpdateReason.HistoricalBar); + indicator.ProcessUpdate(args); + + Assert.Equal(1, indicator.LinesSeries[0].Count); + Assert.True(double.IsFinite(indicator.LinesSeries[0].GetValue(0))); + } + + [Fact] + public void VarianceIndicator_ProcessUpdate_NewBar_ComputesValue() + { + var indicator = new VarianceIndicator { Period = 5 }; + indicator.Initialize(); + + var now = DateTime.UtcNow; + indicator.HistoricalData.AddBar(now, 100, 105, 95, 102); + indicator.HistoricalData.AddBar(now.AddMinutes(1), 102, 108, 100, 106); + + indicator.ProcessUpdate(new UpdateArgs(UpdateReason.HistoricalBar)); + indicator.ProcessUpdate(new UpdateArgs(UpdateReason.NewBar)); + + Assert.Equal(2, indicator.LinesSeries[0].Count); + } + + [Fact] + public void VarianceIndicator_ProcessUpdate_NewTick_ProcessesWithoutError() + { + var indicator = new VarianceIndicator { Period = 5 }; + indicator.Initialize(); + + var now = DateTime.UtcNow; + indicator.HistoricalData.AddBar(now, 100, 105, 95, 102); + + indicator.ProcessUpdate(new UpdateArgs(UpdateReason.HistoricalBar)); + double firstValue = indicator.LinesSeries[0].GetValue(0); + + indicator.ProcessUpdate(new UpdateArgs(UpdateReason.NewTick)); + double secondValue = indicator.LinesSeries[0].GetValue(0); + + Assert.True(double.IsFinite(firstValue)); + Assert.True(double.IsFinite(secondValue)); + } + + [Fact] + public void VarianceIndicator_MultipleUpdates_ProducesCorrectSequence() + { + var indicator = new VarianceIndicator { Period = 5 }; + indicator.Initialize(); + + var now = DateTime.UtcNow; + double[] closes = { 100, 102, 105, 103, 107, 110 }; + + foreach (var close in closes) + { + indicator.HistoricalData.AddBar(now, close, close + 2, close - 2, close); + indicator.ProcessUpdate(new UpdateArgs(UpdateReason.HistoricalBar)); + now = now.AddMinutes(1); + } + + for (int i = 0; i < closes.Length; i++) + { + Assert.True(double.IsFinite(indicator.LinesSeries[0].GetValue(closes.Length - 1 - i))); + } + } + + [Fact] + public void VarianceIndicator_DifferentSourceTypes_Work() + { + var sources = new[] { SourceType.Open, SourceType.High, SourceType.Low, SourceType.Close, SourceType.HL2, SourceType.HLC3 }; + + foreach (var source in sources) + { + var indicator = new VarianceIndicator { Period = 5, Source = source }; + indicator.Initialize(); + + var now = DateTime.UtcNow; + indicator.HistoricalData.AddBar(now, 100, 110, 90, 105); + indicator.ProcessUpdate(new UpdateArgs(UpdateReason.HistoricalBar)); + + Assert.True(double.IsFinite(indicator.LinesSeries[0].GetValue(0)), + $"Source {source} should produce finite value"); + } + } + + [Fact] + public void VarianceIndicator_ShowColdValues_CanBeToggled() + { + var indicator = new VarianceIndicator { ShowColdValues = true }; + Assert.True(indicator.ShowColdValues); + + indicator.ShowColdValues = false; + Assert.False(indicator.ShowColdValues); + } + + [Fact] + public void VarianceIndicator_ConstantInput_ZeroVariance() + { + var indicator = new VarianceIndicator { Period = 5, IsPopulation = true }; + indicator.Initialize(); + + var now = DateTime.UtcNow; + for (int i = 0; i < 10; i++) + { + indicator.HistoricalData.AddBar(now.AddMinutes(i), 100, 100, 100, 100); + indicator.ProcessUpdate(new UpdateArgs(UpdateReason.HistoricalBar)); + } + + double variance = indicator.LinesSeries[0].GetValue(0); + Assert.Equal(0.0, variance, 6); + } + + [Fact] + public void VarianceIndicator_KnownValues_ComputesCorrectly() + { + // For values {2, 4, 4, 4, 5, 5, 7, 9}, population variance = 4.0 + var indicator = new VarianceIndicator { Period = 8, IsPopulation = true }; + indicator.Initialize(); + + double[] values = { 2, 4, 4, 4, 5, 5, 7, 9 }; + var now = DateTime.UtcNow; + foreach (var v in values) + { + indicator.HistoricalData.AddBar(now, v, v, v, v); + indicator.ProcessUpdate(new UpdateArgs(UpdateReason.HistoricalBar)); + now = now.AddMinutes(1); + } + + double variance = indicator.LinesSeries[0].GetValue(0); + Assert.Equal(4.0, variance, 4); + } + + [Fact] + public void VarianceIndicator_SampleVsPopulation_DifferentResults() + { + double[] values = { 2, 4, 4, 4, 5, 5, 7, 9 }; + + var popIndicator = new VarianceIndicator { Period = 8, IsPopulation = true }; + popIndicator.Initialize(); + + var sampIndicator = new VarianceIndicator { Period = 8, IsPopulation = false }; + sampIndicator.Initialize(); + + var now = DateTime.UtcNow; + foreach (var v in values) + { + popIndicator.HistoricalData.AddBar(now, v, v, v, v); + popIndicator.ProcessUpdate(new UpdateArgs(UpdateReason.HistoricalBar)); + + sampIndicator.HistoricalData.AddBar(now, v, v, v, v); + sampIndicator.ProcessUpdate(new UpdateArgs(UpdateReason.HistoricalBar)); + + now = now.AddMinutes(1); + } + + double popVar = popIndicator.LinesSeries[0].GetValue(0); + double sampVar = sampIndicator.LinesSeries[0].GetValue(0); + + // Sample variance (N-1) should be larger than population variance (N) + Assert.True(sampVar > popVar, "Sample variance should be larger than population variance"); + } + + [Fact] + public void VarianceIndicator_OutputIsNonNegative() + { + var indicator = new VarianceIndicator { Period = 5 }; + indicator.Initialize(); + + var now = DateTime.UtcNow; + double[] closes = { 100, 98, 103, 97, 105, 95, 110, 90, 102, 101 }; + + foreach (var close in closes) + { + indicator.HistoricalData.AddBar(now, close, close + 5, close - 5, close); + indicator.ProcessUpdate(new UpdateArgs(UpdateReason.HistoricalBar)); + now = now.AddMinutes(1); + } + + for (int i = 0; i < closes.Length; i++) + { + double val = indicator.LinesSeries[0].GetValue(closes.Length - 1 - i); + Assert.True(val >= 0, $"Variance at index {i} should be non-negative, got {val}"); + } + } + + [Fact] + public void VarianceIndicator_Description_IsSet() + { + var indicator = new VarianceIndicator(); + + Assert.NotNull(indicator.Description); + Assert.NotEmpty(indicator.Description); + Assert.Contains("dispersion", indicator.Description, StringComparison.OrdinalIgnoreCase); + } + + [Fact] + public void VarianceIndicator_DifferentPeriods_ProduceDifferentResults() + { + double[] values = { 100, 102, 98, 105, 97, 110, 95, 108, 101, 103 }; + + var short5 = new VarianceIndicator { Period = 3 }; + short5.Initialize(); + var long10 = new VarianceIndicator { Period = 10 }; + long10.Initialize(); + + var now = DateTime.UtcNow; + foreach (var v in values) + { + short5.HistoricalData.AddBar(now, v, v + 2, v - 2, v); + short5.ProcessUpdate(new UpdateArgs(UpdateReason.HistoricalBar)); + + long10.HistoricalData.AddBar(now, v, v + 2, v - 2, v); + long10.ProcessUpdate(new UpdateArgs(UpdateReason.HistoricalBar)); + + now = now.AddMinutes(1); + } + + double varShort = short5.LinesSeries[0].GetValue(0); + double varLong = long10.LinesSeries[0].GetValue(0); + + Assert.True(double.IsFinite(varShort)); + Assert.True(double.IsFinite(varLong)); + // Different periods should generally give different variance values + Assert.NotEqual(varShort, varLong, 2); + } + + [Fact] + public void VarianceIndicator_LineSeries_HasCorrectProperties() + { + var indicator = new VarianceIndicator(); + indicator.Initialize(); + + var lineSeries = indicator.LinesSeries[0]; + + Assert.Equal(2, lineSeries.Width); + Assert.Equal(LineStyle.Solid, lineSeries.Style); + } +} diff --git a/lib/statistics/variance/Variance.Tests.cs b/lib/statistics/variance/tests/Variance.Tests.cs similarity index 100% rename from lib/statistics/variance/Variance.Tests.cs rename to lib/statistics/variance/tests/Variance.Tests.cs diff --git a/lib/statistics/variance/Variance.Validation.Tests.cs b/lib/statistics/variance/tests/Variance.Validation.Tests.cs similarity index 100% rename from lib/statistics/variance/Variance.Validation.Tests.cs rename to lib/statistics/variance/tests/Variance.Validation.Tests.cs diff --git a/lib/statistics/wavg/Wavg.Tests.cs b/lib/statistics/wavg/tests/Wavg.Tests.cs similarity index 100% rename from lib/statistics/wavg/Wavg.Tests.cs rename to lib/statistics/wavg/tests/Wavg.Tests.cs diff --git a/lib/statistics/wavg/Wavg.Validation.Tests.cs b/lib/statistics/wavg/tests/Wavg.Validation.Tests.cs similarity index 100% rename from lib/statistics/wavg/Wavg.Validation.Tests.cs rename to lib/statistics/wavg/tests/Wavg.Validation.Tests.cs diff --git a/lib/statistics/wins/Wins.Tests.cs b/lib/statistics/wins/tests/Wins.Tests.cs similarity index 100% rename from lib/statistics/wins/Wins.Tests.cs rename to lib/statistics/wins/tests/Wins.Tests.cs diff --git a/lib/statistics/wins/Wins.Validation.Tests.cs b/lib/statistics/wins/tests/Wins.Validation.Tests.cs similarity index 100% rename from lib/statistics/wins/Wins.Validation.Tests.cs rename to lib/statistics/wins/tests/Wins.Validation.Tests.cs diff --git a/lib/statistics/zscore/Zscore.Tests.cs b/lib/statistics/zscore/tests/Zscore.Tests.cs similarity index 100% rename from lib/statistics/zscore/Zscore.Tests.cs rename to lib/statistics/zscore/tests/Zscore.Tests.cs diff --git a/lib/statistics/zscore/Zscore.Validation.Tests.cs b/lib/statistics/zscore/tests/Zscore.Validation.Tests.cs similarity index 100% rename from lib/statistics/zscore/Zscore.Validation.Tests.cs rename to lib/statistics/zscore/tests/Zscore.Validation.Tests.cs diff --git a/lib/statistics/ztest/Ztest.Tests.cs b/lib/statistics/ztest/tests/Ztest.Tests.cs similarity index 100% rename from lib/statistics/ztest/Ztest.Tests.cs rename to lib/statistics/ztest/tests/Ztest.Tests.cs diff --git a/lib/statistics/ztest/Ztest.Validation.Tests.cs b/lib/statistics/ztest/tests/Ztest.Validation.Tests.cs similarity index 100% rename from lib/statistics/ztest/Ztest.Validation.Tests.cs rename to lib/statistics/ztest/tests/Ztest.Validation.Tests.cs diff --git a/lib/trends_FIR/alma/Alma.md b/lib/trends_FIR/alma/Alma.md index 2f6fdb12..f3418b85 100644 --- a/lib/trends_FIR/alma/Alma.md +++ b/lib/trends_FIR/alma/Alma.md @@ -172,122 +172,6 @@ QuanTAlib validates against reference implementations that respect the Gaussian | **TA-Lib** | ❌ | Not included in standard C distribution. | | **Tulip** | ❌ | Not included. | -## C# Implementation Considerations - -### Precomputed Gaussian Weights - -Weights are computed once in the constructor and stored in a `double[]` array: - -```csharp -_weights = new double[period]; -ComputeWeights(_weights, period, offset, sigma, out _invWeightSum); -``` - -The inverse of the weight sum is precomputed for multiplication instead of division in the hot path. - -### State Record Struct with Auto Layout - -Minimal state for bar correction: - -```csharp -[StructLayout(LayoutKind.Auto)] -private record struct State(double LastValidValue, bool IsInitialized); -``` - -The `LayoutKind.Auto` lets the JIT optimize field placement for cache efficiency. - -### SIMD-Optimized Dot Product - -The weighted sum calculation delegates to a SIMD-optimized `DotProduct` extension method: - -```csharp -double sum1 = internalBuf.Slice(head, part1Len).DotProduct(_weights.AsSpan(0, part1Len)); -double sum2 = internalBuf[..head].DotProduct(_weights.AsSpan(part1Len)); -return (sum1 + sum2) * _invWeightSum; -``` - -The dot product leverages AVX2/AVX-512/NEON intrinsics internally, achieving up to 8× speedup. - -### Circular Buffer Handling - -The RingBuffer's internal array is accessed directly to split the dot product across the wrap boundary: - -```csharp -ReadOnlySpan internalBuf = _buffer.InternalBuffer; -int head = _buffer.StartIndex; -int part1Len = _period - head; - -// Part 1: head..end with weights[0..part1Len] -// Part 2: 0..head with weights[part1Len..period] -``` - -This avoids copying the buffer into a contiguous array. - -### Stackalloc/ArrayPool Allocation Strategy - -The static `Calculate` method uses stackalloc for small periods and ArrayPool for large: - -```csharp -double[]? weightsArray = period > 256 ? ArrayPool.Shared.Rent(period) : null; -Span weights = period <= 256 - ? stackalloc double[period] - : weightsArray!.AsSpan(0, period); -``` - -The 256-element threshold balances stack safety with allocation overhead. - -### NaN Handling with Initialization Tracking - -Non-finite inputs are replaced with the last valid value, with explicit tracking for uninitialized state: - -```csharp -private double GetValidValue(double input) -{ - if (double.IsFinite(input)) - return input; - return _state.IsInitialized ? _state.LastValidValue : double.NaN; -} -``` - -This prevents NaN propagation while correctly handling series that start with invalid values. - -### Incremental Weight Sum for Warmup - -During the warmup period, the weight sum is computed incrementally: - -```csharp -if (count < period) -{ - count++; - currentWeightSum += weights[period - count]; -} -``` - -This avoids recalculating the partial sum on each bar during convergence. - -### Separate Internal Update Method - -The `Update` method has a private overload with a `publish` parameter: - -```csharp -private TValue Update(TValue input, bool isNew, bool publish) -``` - -This allows state restoration after batch processing without firing events. - -### Memory Layout - -| Component | Size | Purpose | -| :--- | :--- | :--- | -| `_weights` | 8×period bytes | Precomputed Gaussian weights | -| `_buffer` (RingBuffer) | 32 + 8×period bytes | Sliding window history | -| `_state` | ~16 bytes | LastValidValue, IsInitialized | -| `_p_state` | ~16 bytes | Previous state for rollback | -| Scalars | ~40 bytes | Period, offset, sigma, invWeightSum | -| **Total** | **~104 + 16N bytes** | Per-instance footprint | - -For ALMA(50), total memory is approximately 900 bytes per instance. - ## Common Pitfalls 1. **Offset Abuse**: Setting offset to `0.99` creates a filter that barely filters. It tracks price so closely you might as well use `Price[0]`. Setting it to `0.5` makes it a centered moving average (great for smoothing, terrible for trading due to repainting if used as such, but ALMA does not repaint). The magic is in the `0.85` region. diff --git a/lib/trends_FIR/alma/Alma.Quantower.Tests.cs b/lib/trends_FIR/alma/tests/Alma.Quantower.Tests.cs similarity index 100% rename from lib/trends_FIR/alma/Alma.Quantower.Tests.cs rename to lib/trends_FIR/alma/tests/Alma.Quantower.Tests.cs diff --git a/lib/trends_FIR/alma/Alma.Tests.cs b/lib/trends_FIR/alma/tests/Alma.Tests.cs similarity index 100% rename from lib/trends_FIR/alma/Alma.Tests.cs rename to lib/trends_FIR/alma/tests/Alma.Tests.cs diff --git a/lib/trends_FIR/alma/Alma.Validation.Tests.cs b/lib/trends_FIR/alma/tests/Alma.Validation.Tests.cs similarity index 100% rename from lib/trends_FIR/alma/Alma.Validation.Tests.cs rename to lib/trends_FIR/alma/tests/Alma.Validation.Tests.cs diff --git a/lib/trends_FIR/blma/Blma.md b/lib/trends_FIR/blma/Blma.md index 3b4be815..b9e756f4 100644 --- a/lib/trends_FIR/blma/Blma.md +++ b/lib/trends_FIR/blma/Blma.md @@ -116,145 +116,6 @@ BLMA is validated against a reference implementation using the standard Blackman | **QuanTAlib** | ✅ | Matches theoretical formula. | | **PineScript** | ✅ | Matches PineScript reference logic. | -### C# Implementation Considerations - -The QuanTAlib BLMA implementation emphasizes precomputation and zero-allocation streaming: - -#### Precomputed Weights Array - -Blackman window weights are calculated once in the constructor and reused for every update: - -```csharp -public Blma(int period) -{ - _weights = new double[period]; - _weightSum = CalculateWeights(period, _weights); -} - -private static double CalculateWeights(int n, Span weights) -{ - const double a0 = 0.42; - const double a1 = 0.5; - const double a2 = 0.08; - double invNMinus1 = 1.0 / (n - 1); - - for (int i = 0; i < n; i++) - { - double ratio = i * invNMinus1; - double w = a0 - (a1 * Math.Cos(2.0 * Math.PI * ratio)) - + (a2 * Math.Cos(4.0 * Math.PI * ratio)); - weights[i] = w; - totalWeight += w; - } - return totalWeight; -} -``` - -#### RingBuffer with DotProduct Extension - -The weighted sum uses an optimized dot product that handles circular buffer wraparound: - -```csharp -[MethodImpl(MethodImplOptions.AggressiveInlining)] -private static double CalculateWeightedSum(RingBuffer buffer, ReadOnlySpan weights) -{ - int start = buffer.StartIndex; - int count = buffer.Count; - int capacity = buffer.Capacity; - - if (start + count <= capacity) - { - // Contiguous case - single dot product - return buffer.InternalBuffer.Slice(start, count).DotProduct(weights); - } - - // Wraparound case - two dot products - int firstPartLength = capacity - start; - int secondPartLength = count - firstPartLength; - - double sum1 = buffer.InternalBuffer.Slice(start, firstPartLength).DotProduct(weights[..firstPartLength]); - double sum2 = buffer.InternalBuffer.Slice(0, secondPartLength).DotProduct(weights[firstPartLength..]); - - return sum1 + sum2; -} -``` - -#### Dynamic Warmup Weights - -During warmup (fewer than `period` bars), weights are calculated dynamically using stackalloc: - -```csharp -if (_buffer.Count < _period) -{ - int count = _buffer.Count; - Span currentWeights = stackalloc double[count]; - double currentWeightSum = CalculateWeights(count, currentWeights); - result = ComputeWeightedAverage(currentWeightSum, weightedSum, _buffer.Average()); -} -``` - -#### Stackalloc Strategy for Batch Processing - -The static `Calculate` method uses stackalloc for small periods (≤256) to avoid heap allocation: - -```csharp -Span weights = period <= 256 ? stackalloc double[period] : new double[period]; -double weightSum = CalculateWeights(period, weights); - -// Buffer for warmup weights to avoid stackalloc in loop -Span warmupWeightsBuffer = period <= 256 ? stackalloc double[period] : new double[period]; -``` - -#### NaN Handling with Last-Valid-Value Substitution - -Invalid values are substituted with the last valid value to maintain calculation continuity: - -```csharp -double val = input.Value; -if (!double.IsFinite(val)) -{ - return Last; // Return last result without changing state -} -``` - -In batch mode: -```csharp -double lastValid = double.NaN; -for (int i = 0; i < source.Length; i++) -{ - double val = source[i]; - if (!double.IsFinite(val)) - val = double.IsNaN(lastValid) ? 0 : lastValid; - else - lastValid = val; - // ... -} -``` - -#### AggressiveInlining on Hot Paths - -Critical methods are marked for inlining: - -```csharp -[MethodImpl(MethodImplOptions.AggressiveInlining)] -private static double ComputeWeightedAverage(double weightSum, double weightedSum, double fallbackAverage) -{ - return Math.Abs(weightSum) < double.Epsilon ? fallbackAverage : weightedSum / weightSum; -} -``` - -#### Memory Layout - -| Field | Type | Size | Purpose | -| :--- | :--- | :---: | :--- | -| `_period` | `int` | 4 | Window size | -| `_buffer` | `RingBuffer` | 8 (ref) | Circular price storage | -| `_weights` | `double[]` | 8 (ref) | Precomputed Blackman weights | -| `_weightSum` | `double` | 8 | Sum of weights (precomputed) | -| **Total** | | **~28 bytes** | Per instance (excluding buffer/array internals) | - -**Weight array storage:** `period × 8` bytes (e.g., 160 bytes for period=20) - ### Common Pitfalls * **Lag**: BLMA has more lag than EMA or WMA because it suppresses the most recent data. It is a smoothing filter, not a leading indicator. diff --git a/lib/trends_FIR/blma/Blma.Quantower.Tests.cs b/lib/trends_FIR/blma/tests/Blma.Quantower.Tests.cs similarity index 100% rename from lib/trends_FIR/blma/Blma.Quantower.Tests.cs rename to lib/trends_FIR/blma/tests/Blma.Quantower.Tests.cs diff --git a/lib/trends_FIR/blma/Blma.Tests.cs b/lib/trends_FIR/blma/tests/Blma.Tests.cs similarity index 100% rename from lib/trends_FIR/blma/Blma.Tests.cs rename to lib/trends_FIR/blma/tests/Blma.Tests.cs diff --git a/lib/trends_FIR/blma/Blma.Validation.Tests.cs b/lib/trends_FIR/blma/tests/Blma.Validation.Tests.cs similarity index 100% rename from lib/trends_FIR/blma/Blma.Validation.Tests.cs rename to lib/trends_FIR/blma/tests/Blma.Validation.Tests.cs diff --git a/lib/trends_FIR/bwma/Bwma.md b/lib/trends_FIR/bwma/Bwma.md index 252b720d..9c39c063 100644 --- a/lib/trends_FIR/bwma/Bwma.md +++ b/lib/trends_FIR/bwma/Bwma.md @@ -191,151 +191,6 @@ Self-consistency validation ensures: * NaN handling substitutes last valid value * Reset produces identical results on replay -### C# Implementation Considerations - -The QuanTAlib BWMA implementation optimizes for streaming throughput with precomputed weights and zero-allocation hot paths: - -#### Precomputed Weights with Inverse Sum - -Weights and the inverse of their sum are calculated once in the constructor, replacing division with multiplication: - -```csharp -public Bwma(int period, int order = 0) -{ - _weights = new double[period]; - ComputeWeights(_weights, period, order, out _invWeightSum); -} - -[MethodImpl(MethodImplOptions.AggressiveInlining)] -private static void ComputeWeights(Span weights, int period, int order, out double invWeightSum) -{ - double sum = 0; - double scale = period > 1 ? 2.0 / (period - 1) : 0.0; - double power = order * 0.5 + 0.5; - - for (int i = 0; i < period; i++) - { - double x = period > 1 ? i * scale - 1.0 : 0.0; - double arg = 1.0 - x * x; - double w = arg > 0.0 ? Math.Pow(arg, power) : 0.0; - weights[i] = w; - sum += w; - } - invWeightSum = sum > 0 ? 1.0 / sum : 0.0; // Precompute inverse -} -``` - -#### State Record Struct with Auto Layout - -State uses `LayoutKind.Auto` for compiler-optimized field arrangement: - -```csharp -[StructLayout(LayoutKind.Auto)] -private record struct State -{ - public double LastValidValue; - public bool IsInitialized; -} -private State _state; -private State _p_state; // Previous state for bar correction -``` - -#### FusedMultiplyAdd in Warmup Path - -The warmup calculation uses FMA for coordinate mapping and argument computation: - -```csharp -for (int i = 0; i < p; i++) -{ - double x = Math.FusedMultiplyAdd(i, scale, -1.0); // x = i * scale - 1.0 - double arg = Math.FusedMultiplyAdd(-x, x, 1.0); // arg = 1.0 - x * x - // ... - sum = Math.FusedMultiplyAdd(window[i], w, sum); // sum += window[i] * w -} -``` - -#### Optimized Circular Buffer DotProduct - -The hot path handles ring buffer wraparound with two slice dot products: - -```csharp -[MethodImpl(MethodImplOptions.AggressiveInlining)] -private double CalculateWeightedSum(double fallbackValue) -{ - if (_invWeightSum == 0.0) return fallbackValue; - - ReadOnlySpan internalBuf = _buffer.InternalBuffer; - int head = _buffer.StartIndex; - - int part1Len = _period - head; - double sum1 = internalBuf.Slice(head, part1Len).DotProduct(_weights.AsSpan(0, part1Len)); - double sum2 = internalBuf[..head].DotProduct(_weights.AsSpan(part1Len)); - - return (sum1 + sum2) * _invWeightSum; // Multiply by precomputed inverse -} -``` - -#### ArrayPool for Large Periods in Batch Mode - -The static `Calculate` method uses ArrayPool for periods >256 to avoid large stack allocations: - -```csharp -double[]? weightsArray = period > 256 ? ArrayPool.Shared.Rent(period) : null; -Span weights = period <= 256 - ? stackalloc double[period] - : weightsArray!.AsSpan(0, period); - -double[]? ringArray = period > 256 ? ArrayPool.Shared.Rent(period) : null; -Span ring = period <= 256 - ? stackalloc double[period] - : ringArray!.AsSpan(0, period); - -try -{ - // Processing loop... -} -finally -{ - if (weightsArray != null) ArrayPool.Shared.Return(weightsArray); - if (ringArray != null) ArrayPool.Shared.Return(ringArray); -} -``` - -#### PineScript-Exact Order Handling - -The implementation matches PineScript behavior with special cases for orders 0 and 1: - -```csharp -if (order == 0) -{ - w = arg; // (1 - x²)^1.0 - parabolic -} -else if (order == 1) -{ - w = arg * Math.Sqrt(arg); // (1 - x²)^1.5 - avoids Math.Pow overhead -} -else -{ - w = Math.Pow(arg, power); // (1 - x²)^power -} -``` - -#### Memory Layout - -| Field | Type | Size | Purpose | -| :--- | :--- | :---: | :--- | -| `_period` | `int` | 4 | Window length | -| `_order` | `int` | 4 | Bessel order parameter | -| `_power` | `double` | 8 | Precomputed exponent | -| `_weights` | `double[]` | 8 (ref) | Precomputed weights | -| `_invWeightSum` | `double` | 8 | Inverse of weight sum | -| `_buffer` | `RingBuffer` | 8 (ref) | Circular price storage | -| `_state` | `State` | 16 | Current state (LastValidValue, IsInitialized) | -| `_p_state` | `State` | 16 | Previous state for rollback | -| **Total** | | **~72 bytes** | Per instance (excluding buffer/array internals) | - -**Weight array storage:** `period × 8` bytes (e.g., 160 bytes for period=20) - ## Common Pitfalls 1. **Order Selection Paralysis**: Start with order 0 (parabolic). It's the most balanced choice. Higher orders provide sharper filtering but may over-smooth trend transitions. diff --git a/lib/trends_FIR/bwma/Bwma.Quantower.Tests.cs b/lib/trends_FIR/bwma/tests/Bwma.Quantower.Tests.cs similarity index 100% rename from lib/trends_FIR/bwma/Bwma.Quantower.Tests.cs rename to lib/trends_FIR/bwma/tests/Bwma.Quantower.Tests.cs diff --git a/lib/trends_FIR/bwma/Bwma.Tests.cs b/lib/trends_FIR/bwma/tests/Bwma.Tests.cs similarity index 100% rename from lib/trends_FIR/bwma/Bwma.Tests.cs rename to lib/trends_FIR/bwma/tests/Bwma.Tests.cs diff --git a/lib/trends_FIR/bwma/Bwma.Validation.Tests.cs b/lib/trends_FIR/bwma/tests/Bwma.Validation.Tests.cs similarity index 100% rename from lib/trends_FIR/bwma/Bwma.Validation.Tests.cs rename to lib/trends_FIR/bwma/tests/Bwma.Validation.Tests.cs diff --git a/lib/trends_FIR/conv/Conv.md b/lib/trends_FIR/conv/Conv.md index 9bd46751..8d7954f3 100644 --- a/lib/trends_FIR/conv/Conv.md +++ b/lib/trends_FIR/conv/Conv.md @@ -108,61 +108,6 @@ Validation is performed by reproducing standard moving averages (SMA, WMA, TRIMA | **Tulip** | ✅ | Validated against WMA (using WMA kernel). | | **Ooples** | ✅ | Validated against WMA (using WMA kernel). | -### C# Implementation Considerations - -The QuanTAlib CONV implementation optimizes convolution through pre-allocation and SIMD-accelerated dot products: - -**Defensive Kernel Copy** -```csharp -_kernel = new double[_period]; -Array.Copy(kernel, _kernel, _period); -``` -The kernel is copied to prevent external mutation. This one-time allocation at construction ensures the indicator owns its weight array. - -**State Record Struct** -```csharp -[StructLayout(LayoutKind.Auto)] -private record struct State(double LastValidValue); -private State _state; -private State _p_state; -``` -Minimal state (just last valid value) enables efficient bar correction via `_p_state` snapshot/restore. - -**Circular Buffer Dot Product** -```csharp -int head = _buffer.StartIndex; -int part1Len = _period - head; -result = internalBuf.Slice(head, part1Len).DotProduct(kernelSpan[..part1Len]) - + internalBuf[..head].DotProduct(kernelSpan[part1Len..]); -``` -Full buffer requires two `DotProduct` calls to handle the circular wrap. The `DotProduct` extension leverages AVX2/FMA intrinsics when available. - -**Stackalloc for Batch Processing** -```csharp -Span window = period <= 256 ? stackalloc double[period] : new double[period]; -``` -Small kernels (≤256 elements) use stack allocation to avoid heap pressure during batch operations. - -**Pre-sized Output Collections** -```csharp -CollectionsMarshal.SetCount(t, len); -CollectionsMarshal.SetCount(v, len); -``` -Batch processing pre-sizes lists to avoid reallocation during population. - -**Memory Layout** - -| Field | Type | Size | Notes | -|:------|:-----|-----:|:------| -| `_period` | int | 4B | Kernel length | -| `_kernel` | double[] | 8B + N×8B | Weight array reference + data | -| `_buffer` | RingBuffer | ~40B + N×8B | Circular data buffer | -| `_state` | State | 8B | Current last valid value | -| `_p_state` | State | 8B | Previous state for rollback | -| **Total** | | ~68B + 2N×8B | Plus object overhead | - -For a typical 14-period kernel: ~68 + 224 ≈ **292 bytes** per instance. - ### Common Pitfalls 1. **Kernel Direction**: Our implementation applies the kernel such that the last element of the kernel multiplies the most recent data point. If you import kernels from other DSP libraries, you might need to reverse them. diff --git a/lib/trends_FIR/conv/Conv.Quantower.Tests.cs b/lib/trends_FIR/conv/tests/Conv.Quantower.Tests.cs similarity index 100% rename from lib/trends_FIR/conv/Conv.Quantower.Tests.cs rename to lib/trends_FIR/conv/tests/Conv.Quantower.Tests.cs diff --git a/lib/trends_FIR/conv/Conv.Tests.cs b/lib/trends_FIR/conv/tests/Conv.Tests.cs similarity index 100% rename from lib/trends_FIR/conv/Conv.Tests.cs rename to lib/trends_FIR/conv/tests/Conv.Tests.cs diff --git a/lib/trends_FIR/conv/Conv.Validation.Tests.cs b/lib/trends_FIR/conv/tests/Conv.Validation.Tests.cs similarity index 100% rename from lib/trends_FIR/conv/Conv.Validation.Tests.cs rename to lib/trends_FIR/conv/tests/Conv.Validation.Tests.cs diff --git a/lib/trends_FIR/crma/Crma.Quantower.Tests.cs b/lib/trends_FIR/crma/tests/Crma.Quantower.Tests.cs similarity index 100% rename from lib/trends_FIR/crma/Crma.Quantower.Tests.cs rename to lib/trends_FIR/crma/tests/Crma.Quantower.Tests.cs diff --git a/lib/trends_FIR/crma/Crma.Tests.cs b/lib/trends_FIR/crma/tests/Crma.Tests.cs similarity index 100% rename from lib/trends_FIR/crma/Crma.Tests.cs rename to lib/trends_FIR/crma/tests/Crma.Tests.cs diff --git a/lib/trends_FIR/crma/Crma.Validation.Tests.cs b/lib/trends_FIR/crma/tests/Crma.Validation.Tests.cs similarity index 100% rename from lib/trends_FIR/crma/Crma.Validation.Tests.cs rename to lib/trends_FIR/crma/tests/Crma.Validation.Tests.cs diff --git a/lib/trends_FIR/dwma/Dwma.md b/lib/trends_FIR/dwma/Dwma.md index 0e21e442..36ad7c15 100644 --- a/lib/trends_FIR/dwma/Dwma.md +++ b/lib/trends_FIR/dwma/Dwma.md @@ -94,134 +94,6 @@ Validated against chained WMA implementations in standard libraries. | **Tulip** | ✅ | Validated against chained `wma`. | | **Ooples** | ✅ | Validated against chained `CalculateWeightedMovingAverage`. | -### C# Implementation Considerations - -The QuanTAlib DWMA implementation leverages composition by chaining two WMA instances, inheriting their O(1) streaming performance: - -#### Composition Pattern - -DWMA delegates all calculation to two internal WMA instances: - -```csharp -[SkipLocalsInit] -public sealed class Dwma : AbstractBase -{ - private readonly int _period; - private readonly Wma _wma1; - private readonly Wma _wma2; - - public Dwma(int period) - { - _wma1 = new Wma(period); - _wma2 = new Wma(period); - WarmupPeriod = (period * 2) - 1; // Cumulative warmup - } -} -``` - -#### Minimal Update Logic - -The streaming update is extremely simple - just two WMA calls: - -```csharp -[MethodImpl(MethodImplOptions.AggressiveInlining)] -public override TValue Update(TValue input, bool isNew = true) -{ - if (isNew) _sampleCount++; - - TValue wma1Result = _wma1.Update(input, isNew); - Last = _wma2.Update(wma1Result, isNew); - PubEvent(Last, isNew); - return Last; -} -``` - -This design automatically inherits WMA's bar correction capability - when `isNew=false` is passed, both internal WMAs correctly roll back their state. - -#### ArrayPool for Batch Intermediate Buffer - -The static `Calculate` method uses a temporary buffer for the intermediate WMA result: - -```csharp -[MethodImpl(MethodImplOptions.AggressiveInlining)] -public static void Calculate(ReadOnlySpan source, Span output, int period) -{ - int len = source.Length; - - double[]? tempArray = len > 1024 ? ArrayPool.Shared.Rent(len) : null; - Span temp = len <= 1024 - ? stackalloc double[len] - : tempArray!.AsSpan(0, len); - - try - { - Wma.Batch(source, temp, period); // First pass - Wma.Batch(temp, output, period); // Second pass - } - finally - { - if (tempArray != null) ArrayPool.Shared.Return(tempArray); - } -} -``` - -The threshold (1024) is chosen to balance stack safety vs. allocation overhead. - -#### State Restoration After Batch - -Batch processing restores streaming state by replaying recent bars: - -```csharp -public override TSeries Update(TSeries source) -{ - // Batch calculate - Calculate(source.Values, vSpan, _period); - - // Reset internal state - Reset(); - - // Replay recent bars to restore streaming state - int lookback = WarmupPeriod + 10; - int startIndex = Math.Max(0, len - lookback); - for (int i = startIndex; i < len; i++) - { - Update(new TValue(source.Times[i], source.Values[i])); - } - - _sampleCount = len; - return new TSeries(t, v); -} -``` - -#### Disposal Pattern - -Event subscription is properly cleaned up on disposal: - -```csharp -protected override void Dispose(bool disposing) -{ - if (disposing && _source != null && _handler != null) - { - _source.Pub -= _handler; - } - base.Dispose(disposing); -} -``` - -#### Memory Layout - -| Field | Type | Size | Purpose | -| :--- | :--- | :---: | :--- | -| `_period` | `int` | 4 | Window size | -| `_wma1` | `Wma` | 8 (ref) | First WMA stage | -| `_wma2` | `Wma` | 8 (ref) | Second WMA stage | -| `_source` | `ITValuePublisher?` | 8 (ref) | Event source | -| `_handler` | `TValuePublishedHandler?` | 8 (ref) | Event handler | -| `_sampleCount` | `int` | 4 | Sample counter | -| **Total** | | **~40 bytes** | Per instance (excludes WMA internals) | - -**Total with WMA internals:** Each WMA instance adds ~48 bytes (see WMA docs), so total is ~136 bytes. - ### Common Pitfalls 1. **Lag**: This indicator lags. A lot. Do not use it for entry signals on tight timeframes. Use it for trend filtering (e.g., "only buy if price > DWMA"). diff --git a/lib/trends_FIR/dwma/Dwma.Quantower.Tests.cs b/lib/trends_FIR/dwma/tests/Dwma.Quantower.Tests.cs similarity index 100% rename from lib/trends_FIR/dwma/Dwma.Quantower.Tests.cs rename to lib/trends_FIR/dwma/tests/Dwma.Quantower.Tests.cs diff --git a/lib/trends_FIR/dwma/Dwma.Tests.cs b/lib/trends_FIR/dwma/tests/Dwma.Tests.cs similarity index 100% rename from lib/trends_FIR/dwma/Dwma.Tests.cs rename to lib/trends_FIR/dwma/tests/Dwma.Tests.cs diff --git a/lib/trends_FIR/dwma/Dwma.Validation.Tests.cs b/lib/trends_FIR/dwma/tests/Dwma.Validation.Tests.cs similarity index 100% rename from lib/trends_FIR/dwma/Dwma.Validation.Tests.cs rename to lib/trends_FIR/dwma/tests/Dwma.Validation.Tests.cs diff --git a/lib/trends_FIR/fwma/Fwma.Quantower.Tests.cs b/lib/trends_FIR/fwma/tests/Fwma.Quantower.Tests.cs similarity index 100% rename from lib/trends_FIR/fwma/Fwma.Quantower.Tests.cs rename to lib/trends_FIR/fwma/tests/Fwma.Quantower.Tests.cs diff --git a/lib/trends_FIR/fwma/Fwma.Tests.cs b/lib/trends_FIR/fwma/tests/Fwma.Tests.cs similarity index 100% rename from lib/trends_FIR/fwma/Fwma.Tests.cs rename to lib/trends_FIR/fwma/tests/Fwma.Tests.cs diff --git a/lib/trends_FIR/fwma/Fwma.Validation.Tests.cs b/lib/trends_FIR/fwma/tests/Fwma.Validation.Tests.cs similarity index 100% rename from lib/trends_FIR/fwma/Fwma.Validation.Tests.cs rename to lib/trends_FIR/fwma/tests/Fwma.Validation.Tests.cs diff --git a/lib/trends_FIR/gwma/Gwma.md b/lib/trends_FIR/gwma/Gwma.md index 8a32a70a..caaaa032 100644 --- a/lib/trends_FIR/gwma/Gwma.md +++ b/lib/trends_FIR/gwma/Gwma.md @@ -199,171 +199,6 @@ QuanTAlib validates GWMA against its mathematical definition and internal consis | **Tulip** | ❌ | Not included. | | **Ooples** | ❌ | Not included. | -### C# Implementation Considerations - -The QuanTAlib GWMA implementation optimizes for streaming throughput with precomputed weights and careful state management: - -#### Precomputed Weights with Inverse Sum - -Gaussian weights and the inverse of their sum are calculated once in the constructor: - -```csharp -[MethodImpl(MethodImplOptions.AggressiveInlining)] -private static void ComputeWeights(Span weights, int period, double sigma, out double invWeightSum) -{ - double center = (period - 1) / 2.0; - double invSigmaP = 1.0 / (sigma * period); - double sum = 0; - - for (int i = 0; i < period; i++) - { - double x = (i - center) * invSigmaP; - double w = Math.Exp(-0.5 * x * x); - weights[i] = w; - sum += w; - } - invWeightSum = 1.0 / sum; // Precompute inverse for multiplication -} -``` - -#### State Record Struct with Auto Layout - -State uses `LayoutKind.Auto` for compiler-optimized field arrangement: - -```csharp -[StructLayout(LayoutKind.Auto)] -private record struct State -{ - public double LastValidValue; - public bool IsInitialized; -} -private State _state; -private State _p_state; // Previous state for bar correction -``` - -#### FusedMultiplyAdd in Warmup Path - -The warmup calculation uses FMA for efficient weighted sum accumulation: - -```csharp -private static double CalculateWeightedSumWarmup(ReadOnlySpan window, int p, double sigma, double fallbackValue) -{ - double center = (p - 1) * 0.5; - double invSigmaP = 1.0 / (sigma * p); - double sum = 0.0; - double wSum = 0.0; - - for (int i = 0; i < p; i++) - { - double x = (i - center) * invSigmaP; - double w = Math.Exp(-0.5 * x * x); - sum = Math.FusedMultiplyAdd(window[i], w, sum); // sum += window[i] * w - wSum += w; - } - return wSum > 0.0 ? sum / wSum : fallbackValue; -} -``` - -#### Optimized Circular Buffer DotProduct - -The hot path handles ring buffer wraparound with two slice dot products: - -```csharp -[MethodImpl(MethodImplOptions.AggressiveInlining)] -private double CalculateWeightedSum(double fallbackValue) -{ - if (_invWeightSum == 0.0) return fallbackValue; - - ReadOnlySpan internalBuf = _buffer.InternalBuffer; - int head = _buffer.StartIndex; - - int part1Len = _period - head; - double sum1 = internalBuf.Slice(head, part1Len).DotProduct(_weights.AsSpan(0, part1Len)); - double sum2 = internalBuf[..head].DotProduct(_weights.AsSpan(part1Len)); - - return (sum1 + sum2) * _invWeightSum; -} -``` - -#### ArrayPool for Large Periods in Batch Mode - -The static `Calculate` method uses ArrayPool for periods >256: - -```csharp -double[]? weightsArray = period > 256 ? ArrayPool.Shared.Rent(period) : null; -Span weights = period <= 256 - ? stackalloc double[period] - : weightsArray!.AsSpan(0, period); - -double[]? ringArray = period > 256 ? ArrayPool.Shared.Rent(period) : null; -Span ring = period <= 256 - ? stackalloc double[period] - : ringArray!.AsSpan(0, period); - -try -{ - // Processing loop... -} -finally -{ - if (weightsArray != null) ArrayPool.Shared.Return(weightsArray); - if (ringArray != null) ArrayPool.Shared.Return(ringArray); -} -``` - -#### State Restoration After Batch - -Batch processing restores streaming state by seeding last valid value and replaying: - -```csharp -public override TSeries Update(TSeries source) -{ - Calculate(source.Values, vSpan, _period, _sigma); - - // Restore internal state - _buffer.Clear(); - int windowSize = Math.Min(len, _period); - int startIndex = len - windowSize; - - // Seed last valid value from history before replay window - _state = default; - if (startIndex > 0) - { - for (int i = startIndex - 1; i >= 0; i--) - { - if (double.IsFinite(source.Values[i])) - { - _state.LastValidValue = source.Values[i]; - _state.IsInitialized = true; - break; - } - } - } - - // Replay to rebuild buffer state - for (int i = startIndex; i < len; i++) - { - Update(source[i], isNew: true, publish: false); - } - return new TSeries(t, v); -} -``` - -#### Memory Layout - -| Field | Type | Size | Purpose | -| :--- | :--- | :---: | :--- | -| `_period` | `int` | 4 | Window length | -| `_sigma` | `double` | 8 | Gaussian width parameter | -| `_weights` | `double[]` | 8 (ref) | Precomputed Gaussian weights | -| `_invWeightSum` | `double` | 8 | Inverse of weight sum | -| `_buffer` | `RingBuffer` | 8 (ref) | Circular price storage | -| `_state` | `State` | 16 | Current state (LastValidValue, IsInitialized) | -| `_p_state` | `State` | 16 | Previous state for rollback | -| **Total** | | **~68 bytes** | Per instance (excluding buffer/array internals) | - -**Weight array storage:** `period × 8` bytes (e.g., 160 bytes for period=20) - ## Common Pitfalls 1. **Sigma Extremes**: diff --git a/lib/trends_FIR/gwma/Gwma.Quantower.Tests.cs b/lib/trends_FIR/gwma/tests/Gwma.Quantower.Tests.cs similarity index 100% rename from lib/trends_FIR/gwma/Gwma.Quantower.Tests.cs rename to lib/trends_FIR/gwma/tests/Gwma.Quantower.Tests.cs diff --git a/lib/trends_FIR/gwma/Gwma.Tests.cs b/lib/trends_FIR/gwma/tests/Gwma.Tests.cs similarity index 100% rename from lib/trends_FIR/gwma/Gwma.Tests.cs rename to lib/trends_FIR/gwma/tests/Gwma.Tests.cs diff --git a/lib/trends_FIR/gwma/Gwma.Validation.Tests.cs b/lib/trends_FIR/gwma/tests/Gwma.Validation.Tests.cs similarity index 100% rename from lib/trends_FIR/gwma/Gwma.Validation.Tests.cs rename to lib/trends_FIR/gwma/tests/Gwma.Validation.Tests.cs diff --git a/lib/trends_FIR/hamma/Hamma.md b/lib/trends_FIR/hamma/Hamma.md index a87136d6..f3fc02ea 100644 --- a/lib/trends_FIR/hamma/Hamma.md +++ b/lib/trends_FIR/hamma/Hamma.md @@ -184,76 +184,6 @@ QuanTAlib validates HAMMA against its mathematical definition and internal consi | **Tulip** | ❌ | Not included. | | **Ooples** | ❌ | Not included. | -### C# Implementation Considerations - -The QuanTAlib HAMMA implementation optimizes Hamming window convolution through precomputation and SIMD-accelerated dot products: - -**Precomputed Weights with Inverse Sum** -```csharp -ComputeWeights(_weights, period, out _invWeightSum); -// ... -double twoPiOverPm1 = 2.0 * Math.PI / (period - 1); -for (int i = 0; i < period; i++) -{ - double w = 0.54 - 0.46 * Math.Cos(twoPiOverPm1 * i); - weights[i] = w; - sum += w; -} -invWeightSum = 1.0 / sum; -``` -Trigonometric operations computed once at construction. Normalization uses multiplication by precomputed inverse rather than division per tick. - -**State Record Struct** -```csharp -[StructLayout(LayoutKind.Auto)] -private record struct State(double LastValidValue, bool IsInitialized); -private State _state; -private State _p_state; -``` -Compiler optimizes field layout. The `IsInitialized` flag tracks whether valid data has been seen for proper NaN handling. - -**SIMD-Accelerated Circular Buffer Dot Product** -```csharp -int part1Len = _period - head; -double sum1 = internalBuf.Slice(head, part1Len).DotProduct(_weights.AsSpan(0, part1Len)); -double sum2 = internalBuf[..head].DotProduct(_weights.AsSpan(part1Len)); -return (sum1 + sum2) * _invWeightSum; -``` -Full buffer splits into two `DotProduct` calls to handle circular wrap. The extension leverages AVX2/FMA intrinsics when available. - -**Dual Allocation Strategy for Batch** -```csharp -double[]? weightsArray = period > 256 ? ArrayPool.Shared.Rent(period) : null; -Span weights = period <= 256 - ? stackalloc double[period] - : weightsArray!.AsSpan(0, period); -``` -Small periods use stack allocation; large periods use `ArrayPool` to avoid heap pressure while respecting stack limits. - -**Incremental Weight Sum During Warmup** -```csharp -if (count < period) -{ - count++; - currentWeightSum += weights[period - count]; -} -``` -Partial buffer normalization accumulates weight sum incrementally rather than recalculating each tick. - -**Memory Layout** - -| Field | Type | Size | Notes | -|:------|:-----|-----:|:------| -| `_period` | int | 4B | Window length | -| `_weights` | double[] | 8B + L×8B | Hamming coefficients | -| `_invWeightSum` | double | 8B | Precomputed 1/Σw | -| `_buffer` | RingBuffer | ~40B + L×8B | Circular data buffer | -| `_state` | State | 16B | Last valid + initialized flag | -| `_p_state` | State | 16B | Previous state for rollback | -| **Total** | | ~92B + 2L×8B | Plus object overhead | - -For a typical 14-period: ~92 + 224 ≈ **316 bytes** per instance. - ## Common Pitfalls 1. **Confusing Hamming and Hanning**: Hamming uses 0.54/0.46 coefficients with edge weights of 0.08. Hanning uses 0.5/0.5 with edge weights of 0.0. They're different windows with different properties. diff --git a/lib/trends_FIR/hamma/Hamma.Quantower.Tests.cs b/lib/trends_FIR/hamma/tests/Hamma.Quantower.Tests.cs similarity index 100% rename from lib/trends_FIR/hamma/Hamma.Quantower.Tests.cs rename to lib/trends_FIR/hamma/tests/Hamma.Quantower.Tests.cs diff --git a/lib/trends_FIR/hamma/Hamma.Tests.cs b/lib/trends_FIR/hamma/tests/Hamma.Tests.cs similarity index 100% rename from lib/trends_FIR/hamma/Hamma.Tests.cs rename to lib/trends_FIR/hamma/tests/Hamma.Tests.cs diff --git a/lib/trends_FIR/hamma/Hamma.Validation.Tests.cs b/lib/trends_FIR/hamma/tests/Hamma.Validation.Tests.cs similarity index 100% rename from lib/trends_FIR/hamma/Hamma.Validation.Tests.cs rename to lib/trends_FIR/hamma/tests/Hamma.Validation.Tests.cs diff --git a/lib/trends_FIR/hanma/Hanma.md b/lib/trends_FIR/hanma/Hanma.md index fd647237..bf6428ad 100644 --- a/lib/trends_FIR/hanma/Hanma.md +++ b/lib/trends_FIR/hanma/Hanma.md @@ -185,78 +185,6 @@ QuanTAlib validates HANMA against its mathematical definition and internal consi | **Tulip** | ❌ | Not included. | | **Ooples** | ❌ | Not included. | -### C# Implementation Considerations - -The QuanTAlib HANMA implementation optimizes Hanning window convolution through precomputation and SIMD-accelerated dot products: - -**Precomputed Weights with Inverse Sum** -```csharp -ComputeWeights(_weights, period, out _invWeightSum); -// ... -double twoPiOverPm1 = 2.0 * Math.PI / (period - 1); -for (int i = 0; i < period; i++) -{ - double w = 0.5 * (1.0 - Math.Cos(twoPiOverPm1 * i)); - weights[i] = w; - sum += w; -} -invWeightSum = 1.0 / sum; -``` -Trigonometric operations computed once at construction. Normalization uses multiplication by precomputed inverse rather than division per tick. - -**State Record Struct** -```csharp -[StructLayout(LayoutKind.Auto)] -private record struct State(double LastValidValue, bool IsInitialized); -private State _state; -private State _p_state; -``` -Compiler optimizes field layout. The `IsInitialized` flag tracks whether valid data has been seen for proper NaN handling. - -**Zero-Weight Edge Case Handling** -```csharp -if (wSum <= 0) -{ - double avg = 0; - for (int i = 0; i < count; i++) - avg += bufferSpan[i]; - return avg / count; -} -``` -Hanning's zero edge weights can cause zero weight sum during warmup. Falls back to simple average when weight sum is zero. - -**SIMD-Accelerated Circular Buffer Dot Product** -```csharp -int part1Len = _period - head; -double sum1 = internalBuf.Slice(head, part1Len).DotProduct(_weights.AsSpan(0, part1Len)); -double sum2 = internalBuf[..head].DotProduct(_weights.AsSpan(part1Len)); -return (sum1 + sum2) * _invWeightSum; -``` -Full buffer splits into two `DotProduct` calls to handle circular wrap. The extension leverages AVX2/FMA intrinsics when available. - -**Dual Allocation Strategy for Batch** -```csharp -double[]? weightsArray = period > 256 ? ArrayPool.Shared.Rent(period) : null; -Span weights = period <= 256 - ? stackalloc double[period] - : weightsArray!.AsSpan(0, period); -``` -Small periods use stack allocation; large periods use `ArrayPool` to avoid heap pressure while respecting stack limits. - -**Memory Layout** - -| Field | Type | Size | Notes | -|:------|:-----|-----:|:------| -| `_period` | int | 4B | Window length | -| `_weights` | double[] | 8B + L×8B | Hanning coefficients | -| `_invWeightSum` | double | 8B | Precomputed 1/Σw | -| `_buffer` | RingBuffer | ~40B + L×8B | Circular data buffer | -| `_state` | State | 16B | Last valid + initialized flag | -| `_p_state` | State | 16B | Previous state for rollback | -| **Total** | | ~92B + 2L×8B | Plus object overhead | - -For a typical 14-period: ~92 + 224 ≈ **316 bytes** per instance. - ## Common Pitfalls 1. **Confusing Hanning and Hamming**: Hanning uses 0.5 coefficient with edge weights of exactly 0.0. Hamming uses 0.54/0.46 with edge weights of 0.08. They're different windows with different properties. diff --git a/lib/trends_FIR/hanma/Hanma.Quantower.Tests.cs b/lib/trends_FIR/hanma/tests/Hanma.Quantower.Tests.cs similarity index 100% rename from lib/trends_FIR/hanma/Hanma.Quantower.Tests.cs rename to lib/trends_FIR/hanma/tests/Hanma.Quantower.Tests.cs diff --git a/lib/trends_FIR/hanma/Hanma.Tests.cs b/lib/trends_FIR/hanma/tests/Hanma.Tests.cs similarity index 100% rename from lib/trends_FIR/hanma/Hanma.Tests.cs rename to lib/trends_FIR/hanma/tests/Hanma.Tests.cs diff --git a/lib/trends_FIR/hanma/Hanma.Validation.Tests.cs b/lib/trends_FIR/hanma/tests/Hanma.Validation.Tests.cs similarity index 100% rename from lib/trends_FIR/hanma/Hanma.Validation.Tests.cs rename to lib/trends_FIR/hanma/tests/Hanma.Validation.Tests.cs diff --git a/lib/trends_FIR/hend/Hend.Quantower.Tests.cs b/lib/trends_FIR/hend/tests/Hend.Quantower.Tests.cs similarity index 100% rename from lib/trends_FIR/hend/Hend.Quantower.Tests.cs rename to lib/trends_FIR/hend/tests/Hend.Quantower.Tests.cs diff --git a/lib/trends_FIR/hend/Hend.Tests.cs b/lib/trends_FIR/hend/tests/Hend.Tests.cs similarity index 100% rename from lib/trends_FIR/hend/Hend.Tests.cs rename to lib/trends_FIR/hend/tests/Hend.Tests.cs diff --git a/lib/trends_FIR/hend/Hend.Validation.Tests.cs b/lib/trends_FIR/hend/tests/Hend.Validation.Tests.cs similarity index 100% rename from lib/trends_FIR/hend/Hend.Validation.Tests.cs rename to lib/trends_FIR/hend/tests/Hend.Validation.Tests.cs diff --git a/lib/trends_FIR/hma/Hma.md b/lib/trends_FIR/hma/Hma.md index 5518ee34..9a5df7a7 100644 --- a/lib/trends_FIR/hma/Hma.md +++ b/lib/trends_FIR/hma/Hma.md @@ -108,133 +108,3 @@ Discrepancies exist due to different rounding methods for integer periods. * **Ooples**: Uses `Math.Round` (nearest integer). This results in different effective periods for $N=14$ ($\sqrt{14} \approx 3.74 \to 3$ vs $4$) and others where the fractional part $\ge 0.5$. Validation tests match exactly for periods where rounding logic aligns (e.g., $N=9, 20, 50$). - -## C# Implementation Considerations - -### Compositional Architecture - -HMA composes three independent `Wma` instances rather than implementing custom logic: - -```csharp -_wmaFull = new Wma(period); -_wmaHalf = new Wma(halfPeriod); -_wmaSqrt = new Wma(_sqrtPeriod); -``` - -This leverages WMA's optimized O(1) implementation for each component, maintaining the zero-allocation property. - -### Streaming Update Pipeline - -The hot path chains the three WMA updates with minimal intermediate allocation: - -```csharp -TValue full = _wmaFull.Update(input, isNew); -TValue half = _wmaHalf.Update(input, isNew); -double intermediate = (2.0 * half.Value) - full.Value; -Last = _wmaSqrt.Update(new TValue(input.Time, intermediate), isNew); -``` - -The intermediate value computation uses scalar arithmetic—no buffer required. - -### ArrayPool for Batch Processing - -The static `Calculate` method rents arrays from `ArrayPool` for temporary storage: - -```csharp -double[] rentedFull = System.Buffers.ArrayPool.Shared.Rent(len); -double[] rentedHalf = System.Buffers.ArrayPool.Shared.Rent(len); -try -{ - Wma.Batch(source, fullWma, period); - Wma.Batch(source, halfWma, halfPeriod); - CalculateIntermediate(halfWma, fullWma, intermediate); - Wma.Batch(intermediate, output, sqrtPeriod); -} -finally -{ - System.Buffers.ArrayPool.Shared.Return(rentedFull); - System.Buffers.ArrayPool.Shared.Return(rentedHalf); -} -``` - -Buffer reuse: the `halfWma` array doubles as the `intermediate` buffer since values are consumed before being overwritten. - -### SIMD-Accelerated Intermediate Calculation - -The combiner step $2 \times \text{WMA}_{half} - \text{WMA}_{full}$ is fully vectorized: - -```csharp -if (Avx512F.IsSupported && len >= Vector512.Count) -{ - var vTwo = Vector512.Create(2.0); - var vResult = Avx512F.Subtract(Avx512F.Multiply(vHalf, vTwo), vFull); -} -else if (Avx2.IsSupported && len >= Vector256.Count) -{ - var vTwo = Vector256.Create(2.0); - var vResult = Avx.Subtract(Avx.Multiply(vHalf, vTwo), vFull); -} -else if (AdvSimd.Arm64.IsSupported && len >= Vector128.Count) -{ - var vTwo = Vector128.Create(2.0); - var vResult = AdvSimd.Arm64.Subtract(AdvSimd.Arm64.Multiply(vHalf, vTwo), vFull); -} -``` - -This achieves 8× throughput on AVX-512, 4× on AVX2, and 2× on NEON. - -### Unsafe Memory Access - -Direct memory references eliminate bounds checking in the SIMD loops: - -```csharp -ref double halfRef = ref MemoryMarshal.GetReference(halfWma); -ref double fullRef = ref MemoryMarshal.GetReference(fullWma); -ref double outRef = ref MemoryMarshal.GetReference(output); - -var vHalf = Vector512.LoadUnsafe(ref Unsafe.Add(ref halfRef, i)); -``` - -### State Replay for TSeries Update - -After batch calculation, streaming state is restored by replaying the trailing window: - -```csharp -int lookback = _period + _sqrtPeriod + 10; -int startIndex = Math.Max(0, len - lookback); -for (int i = startIndex; i < len; i++) -{ - Update(new TValue(source.Times[i], source.Values[i])); -} -``` - -This ensures subsequent streaming updates produce correct results after a batch operation. - -### Integer Period Truncation - -Periods use integer truncation (not rounding) for consistent behavior: - -```csharp -int halfPeriod = period / 2; -_sqrtPeriod = (int)Math.Sqrt(period); -``` - -This differs from some implementations that use `Math.Round`, affecting results for certain periods. - -### Memory Layout - -| Component | Size | Purpose | -| :--- | :--- | :--- | -| `_wmaFull` | ~152 + 8×period bytes | Full-period WMA | -| `_wmaHalf` | ~152 + 4×period bytes | Half-period WMA | -| `_wmaSqrt` | ~152 + 8×√period bytes | Smoothing WMA | -| Scalars | ~32 bytes | Period values, sample count | -| **Total** | **~488 + 12N + 8√N bytes** | Per-instance footprint | - -For HMA(100), total memory is approximately 1.7 KB per instance (three WMA instances combined). - -### Common Pitfalls - -1. **Overshoot**: Like DEMA, HMA can overshoot price turns because of the lag correction. -2. **Period Sensitivity**: The $\sqrt{N}$ smoothing is hardcoded into the definition. You can't easily tweak the smoothing independently of the lag correction without breaking the "Hull" definition. -3. **Integer Math**: The periods $N/2$ and $\sqrt{N}$ are rounded to integers. This can cause slight discrepancies between implementations depending on rounding rules. Standard integer truncation is used in QuanTAlib. diff --git a/lib/trends_FIR/hma/Hma.Quantower.Tests.cs b/lib/trends_FIR/hma/tests/Hma.Quantower.Tests.cs similarity index 100% rename from lib/trends_FIR/hma/Hma.Quantower.Tests.cs rename to lib/trends_FIR/hma/tests/Hma.Quantower.Tests.cs diff --git a/lib/trends_FIR/hma/Hma.Tests.cs b/lib/trends_FIR/hma/tests/Hma.Tests.cs similarity index 100% rename from lib/trends_FIR/hma/Hma.Tests.cs rename to lib/trends_FIR/hma/tests/Hma.Tests.cs diff --git a/lib/trends_FIR/hma/Hma.Validation.Tests.cs b/lib/trends_FIR/hma/tests/Hma.Validation.Tests.cs similarity index 100% rename from lib/trends_FIR/hma/Hma.Validation.Tests.cs rename to lib/trends_FIR/hma/tests/Hma.Validation.Tests.cs diff --git a/lib/trends_FIR/ilrs/Ilrs.Quantower.Tests.cs b/lib/trends_FIR/ilrs/tests/Ilrs.Quantower.Tests.cs similarity index 100% rename from lib/trends_FIR/ilrs/Ilrs.Quantower.Tests.cs rename to lib/trends_FIR/ilrs/tests/Ilrs.Quantower.Tests.cs diff --git a/lib/trends_FIR/ilrs/Ilrs.Tests.cs b/lib/trends_FIR/ilrs/tests/Ilrs.Tests.cs similarity index 100% rename from lib/trends_FIR/ilrs/Ilrs.Tests.cs rename to lib/trends_FIR/ilrs/tests/Ilrs.Tests.cs diff --git a/lib/trends_FIR/ilrs/Ilrs.Validation.Tests.cs b/lib/trends_FIR/ilrs/tests/Ilrs.Validation.Tests.cs similarity index 100% rename from lib/trends_FIR/ilrs/Ilrs.Validation.Tests.cs rename to lib/trends_FIR/ilrs/tests/Ilrs.Validation.Tests.cs diff --git a/lib/trends_FIR/kaiser/Kaiser.Quantower.Tests.cs b/lib/trends_FIR/kaiser/tests/Kaiser.Quantower.Tests.cs similarity index 100% rename from lib/trends_FIR/kaiser/Kaiser.Quantower.Tests.cs rename to lib/trends_FIR/kaiser/tests/Kaiser.Quantower.Tests.cs diff --git a/lib/trends_FIR/kaiser/Kaiser.Tests.cs b/lib/trends_FIR/kaiser/tests/Kaiser.Tests.cs similarity index 100% rename from lib/trends_FIR/kaiser/Kaiser.Tests.cs rename to lib/trends_FIR/kaiser/tests/Kaiser.Tests.cs diff --git a/lib/trends_FIR/kaiser/Kaiser.Validation.Tests.cs b/lib/trends_FIR/kaiser/tests/Kaiser.Validation.Tests.cs similarity index 100% rename from lib/trends_FIR/kaiser/Kaiser.Validation.Tests.cs rename to lib/trends_FIR/kaiser/tests/Kaiser.Validation.Tests.cs diff --git a/lib/trends_FIR/lanczos/Lanczos.Quantower.Tests.cs b/lib/trends_FIR/lanczos/tests/Lanczos.Quantower.Tests.cs similarity index 100% rename from lib/trends_FIR/lanczos/Lanczos.Quantower.Tests.cs rename to lib/trends_FIR/lanczos/tests/Lanczos.Quantower.Tests.cs diff --git a/lib/trends_FIR/lanczos/Lanczos.Tests.cs b/lib/trends_FIR/lanczos/tests/Lanczos.Tests.cs similarity index 100% rename from lib/trends_FIR/lanczos/Lanczos.Tests.cs rename to lib/trends_FIR/lanczos/tests/Lanczos.Tests.cs diff --git a/lib/trends_FIR/lanczos/Lanczos.Validation.Tests.cs b/lib/trends_FIR/lanczos/tests/Lanczos.Validation.Tests.cs similarity index 100% rename from lib/trends_FIR/lanczos/Lanczos.Validation.Tests.cs rename to lib/trends_FIR/lanczos/tests/Lanczos.Validation.Tests.cs diff --git a/lib/trends_FIR/lsma/Lsma.md b/lib/trends_FIR/lsma/Lsma.md index bb0fa531..ccf5546e 100644 --- a/lib/trends_FIR/lsma/Lsma.md +++ b/lib/trends_FIR/lsma/Lsma.md @@ -109,137 +109,6 @@ Validated against Skender. | **Tulip** | N/A | Not implemented. | | **Ooples** | N/A | Not implemented. | -### C# Implementation Considerations - -The QuanTAlib LSMA implementation achieves O(1) streaming updates through running sum maintenance with several optimizations: - -#### O(1) Running Sum Algorithm - -The implementation maintains two running sums (`SumY`, `SumXY`) that enable constant-time updates instead of O(N) recalculation: - -```csharp -// O(1) update for sum_xy: sum_xy_new = sum_xy_old + sum_y_prev - n * oldest -_state.SumXY = Math.FusedMultiplyAdd(-_period, oldest, _state.SumXY + prev_sum_y); - -// O(1) update for sum_y -_state.SumY = _state.SumY - oldest + val; -``` - -#### Precomputed Constants - -Mathematical constants are computed once in the constructor to avoid redundant calculations: - -```csharp -// sum_x = 0 + 1 + ... + (n-1) = n(n-1)/2 -_sum_x = 0.5 * period * (period - 1); - -// sum_x2 = 0² + ... + (n-1)² = (n-1)n(2n-1)/6 -double sum_x2 = (period - 1.0) * period * (2.0 * period - 1.0) / 6.0; - -// denominator = n * sum_x2 - sum_x² -_denominator = period * sum_x2 - _sum_x * _sum_x; -``` - -#### State Record Struct - -State uses `LayoutKind.Auto` for compiler-optimized field ordering: - -```csharp -[StructLayout(LayoutKind.Auto)] -private record struct State(double SumY, double SumXY, double LastVal, double LastValidValue); -private State _state; -private State _p_state; // Previous state for bar correction -``` - -#### FusedMultiplyAdd Usage - -FMA is used extensively for slope, intercept, and endpoint calculations: - -```csharp -double m = Math.FusedMultiplyAdd(n, _state.SumXY, -sx * _state.SumY) / denom; -double b = Math.FusedMultiplyAdd(-m, sx, _state.SumY) / n; -result = Math.FusedMultiplyAdd(-m, _offset, b); -``` - -#### Periodic Resync - -Running sums accumulate floating-point drift; periodic resync every 1000 ticks corrects this: - -```csharp -private const int ResyncInterval = 1000; - -private void Resync() -{ - _state.SumY = _buffer.Sum; - _state.SumXY = 0; - var span = _buffer.GetSpan(); - for (int i = 0; i < span.Length; i++) - { - int x = span.Length - 1 - i; - _state.SumXY = Math.FusedMultiplyAdd(x, span[i], _state.SumXY); - } -} -``` - -#### Stackalloc/ArrayPool Strategy - -The static `Calculate` method uses stackalloc for small periods (≤256) to avoid heap allocation: - -```csharp -const int StackAllocThreshold = 256; -Span buffer = period <= StackAllocThreshold - ? stackalloc double[period] - : new double[period]; -``` - -#### Thread-Safe Disposal - -Disposal uses atomic operations for idempotent, thread-safe cleanup: - -```csharp -protected override void Dispose(bool disposing) -{ - if (Interlocked.CompareExchange(ref _disposed, 1, 0) == 0 && _source != null) - { - _source.Pub -= _handler; - _source = null; - } - base.Dispose(disposing); -} -``` - -#### NaN Handling - -Invalid values are replaced with the last valid value to maintain calculation integrity: - -```csharp -[MethodImpl(MethodImplOptions.AggressiveInlining)] -private double GetValidValue(double input) -{ - if (double.IsFinite(input)) - { - _state.LastValidValue = input; - return input; - } - return _state.LastValidValue; -} -``` - -#### Memory Layout - -| Field | Type | Size | Purpose | -| :--- | :--- | :---: | :--- | -| `_period` | `int` | 4 | Lookback window | -| `_offset` | `int` | 4 | Forecast offset | -| `_buffer` | `RingBuffer` | 8 (ref) | Circular storage | -| `_sum_x` | `double` | 8 | Precomputed Σx | -| `_denominator` | `double` | 8 | Precomputed denominator | -| `_state` | `State` | 32 | Current state (SumY, SumXY, LastVal, LastValidValue) | -| `_p_state` | `State` | 32 | Previous state for rollback | -| `_tickCount` | `int` | 4 | Resync counter | -| `_disposed` | `int` | 4 | Atomic disposal flag | -| **Total** | | **~104 bytes** | Per instance (excluding RingBuffer internal storage) | - ### Common Pitfalls 1. **Overshoot**: Because it projects a trend, LSMA will overshoot significantly when the trend reverses. It assumes the trend continues. diff --git a/lib/trends_FIR/lsma/Lsma.Quantower.Tests.cs b/lib/trends_FIR/lsma/tests/Lsma.Quantower.Tests.cs similarity index 100% rename from lib/trends_FIR/lsma/Lsma.Quantower.Tests.cs rename to lib/trends_FIR/lsma/tests/Lsma.Quantower.Tests.cs diff --git a/lib/trends_FIR/lsma/Lsma.Tests.cs b/lib/trends_FIR/lsma/tests/Lsma.Tests.cs similarity index 100% rename from lib/trends_FIR/lsma/Lsma.Tests.cs rename to lib/trends_FIR/lsma/tests/Lsma.Tests.cs diff --git a/lib/trends_FIR/lsma/Lsma.Validation.Tests.cs b/lib/trends_FIR/lsma/tests/Lsma.Validation.Tests.cs similarity index 100% rename from lib/trends_FIR/lsma/Lsma.Validation.Tests.cs rename to lib/trends_FIR/lsma/tests/Lsma.Validation.Tests.cs diff --git a/lib/trends_FIR/nlma/Nlma.Quantower.Tests.cs b/lib/trends_FIR/nlma/tests/Nlma.Quantower.Tests.cs similarity index 100% rename from lib/trends_FIR/nlma/Nlma.Quantower.Tests.cs rename to lib/trends_FIR/nlma/tests/Nlma.Quantower.Tests.cs diff --git a/lib/trends_FIR/nlma/Nlma.Tests.cs b/lib/trends_FIR/nlma/tests/Nlma.Tests.cs similarity index 100% rename from lib/trends_FIR/nlma/Nlma.Tests.cs rename to lib/trends_FIR/nlma/tests/Nlma.Tests.cs diff --git a/lib/trends_FIR/nlma/Nlma.Validation.Tests.cs b/lib/trends_FIR/nlma/tests/Nlma.Validation.Tests.cs similarity index 100% rename from lib/trends_FIR/nlma/Nlma.Validation.Tests.cs rename to lib/trends_FIR/nlma/tests/Nlma.Validation.Tests.cs diff --git a/lib/trends_FIR/nyqma/Nyqma.Quantower.Tests.cs b/lib/trends_FIR/nyqma/tests/Nyqma.Quantower.Tests.cs similarity index 100% rename from lib/trends_FIR/nyqma/Nyqma.Quantower.Tests.cs rename to lib/trends_FIR/nyqma/tests/Nyqma.Quantower.Tests.cs diff --git a/lib/trends_FIR/nyqma/Nyqma.Tests.cs b/lib/trends_FIR/nyqma/tests/Nyqma.Tests.cs similarity index 100% rename from lib/trends_FIR/nyqma/Nyqma.Tests.cs rename to lib/trends_FIR/nyqma/tests/Nyqma.Tests.cs diff --git a/lib/trends_FIR/nyqma/Nyqma.Validation.Tests.cs b/lib/trends_FIR/nyqma/tests/Nyqma.Validation.Tests.cs similarity index 100% rename from lib/trends_FIR/nyqma/Nyqma.Validation.Tests.cs rename to lib/trends_FIR/nyqma/tests/Nyqma.Validation.Tests.cs diff --git a/lib/trends_FIR/parzen/Parzen.Quantower.Tests.cs b/lib/trends_FIR/parzen/tests/Parzen.Quantower.Tests.cs similarity index 100% rename from lib/trends_FIR/parzen/Parzen.Quantower.Tests.cs rename to lib/trends_FIR/parzen/tests/Parzen.Quantower.Tests.cs diff --git a/lib/trends_FIR/parzen/Parzen.Tests.cs b/lib/trends_FIR/parzen/tests/Parzen.Tests.cs similarity index 100% rename from lib/trends_FIR/parzen/Parzen.Tests.cs rename to lib/trends_FIR/parzen/tests/Parzen.Tests.cs diff --git a/lib/trends_FIR/parzen/Parzen.Validation.Tests.cs b/lib/trends_FIR/parzen/tests/Parzen.Validation.Tests.cs similarity index 100% rename from lib/trends_FIR/parzen/Parzen.Validation.Tests.cs rename to lib/trends_FIR/parzen/tests/Parzen.Validation.Tests.cs diff --git a/lib/trends_FIR/pma/Pma.Quantower.Tests.cs b/lib/trends_FIR/pma/tests/Pma.Quantower.Tests.cs similarity index 100% rename from lib/trends_FIR/pma/Pma.Quantower.Tests.cs rename to lib/trends_FIR/pma/tests/Pma.Quantower.Tests.cs diff --git a/lib/trends_FIR/pma/Pma.Tests.cs b/lib/trends_FIR/pma/tests/Pma.Tests.cs similarity index 100% rename from lib/trends_FIR/pma/Pma.Tests.cs rename to lib/trends_FIR/pma/tests/Pma.Tests.cs diff --git a/lib/trends_FIR/pma/Pma.Validation.Tests.cs b/lib/trends_FIR/pma/tests/Pma.Validation.Tests.cs similarity index 100% rename from lib/trends_FIR/pma/Pma.Validation.Tests.cs rename to lib/trends_FIR/pma/tests/Pma.Validation.Tests.cs diff --git a/lib/trends_FIR/pwma/Pwma.md b/lib/trends_FIR/pwma/Pwma.md index 75ab069c..e74ebec1 100644 --- a/lib/trends_FIR/pwma/Pwma.md +++ b/lib/trends_FIR/pwma/Pwma.md @@ -97,95 +97,3 @@ Validated against Ooples. | **TA-Lib** | N/A | Not implemented | | **Tulip** | N/A | Not implemented. | - -## C# Implementation Considerations - -QuanTAlib's PWMA uses triple cascading sums to achieve O(1) streaming updates. The implementation demonstrates several high-performance patterns: - -### State Management - -```csharp -[StructLayout(LayoutKind.Auto)] -private record struct State( - double Sum, // Running sum (S1) - double WSum, // Weighted sum (S2) - double PSum, // Parabolic sum (S3) - double LastInput, - double LastValidValue, - int TickCount) -``` - -The state captures all three cascading sums needed for the O(1) update formula. `TickCount` tracks iterations for periodic resync. - -### Key Optimizations - -| Technique | Implementation | Benefit | -| :--- | :--- | :--- | -| **Precomputed divisor** | `_divisor = period * (period + 1.0) * (2.0 * period + 1.0) / 6.0` | Eliminates division in hot path | -| **FMA cascade** | All three sum updates use `FusedMultiplyAdd` | Hardware-accelerated multiply-add | -| **Dual buffer** | `_buffer` + `_p_buffer` for bar correction | O(1) state restoration on `isNew=false` | -| **Periodic resync** | Full recalculation every 1000 ticks | Bounds floating-point drift | -| **stackalloc** | Batch `Calculate` uses stack for period ≤ 512 | Zero heap allocation | - -### FMA in Cascade Updates - -The cascading sum formulas map directly to FMA operations: - -```csharp -// S1 update (simple running sum) -double newSum = _state.Sum - oldest + newest; - -// S2 update: S2_new = S2_old - S1_old + N×newest -double newWSum = Math.FusedMultiplyAdd(period, newest, _state.WSum - _state.Sum); - -// S3 update: S3_new = S3_old - 2×S2_old + S1_old + N²×newest -double newPSum = Math.FusedMultiplyAdd(period * period, newest, - _state.PSum - 2 * oldWSum + oldSum); -``` - -### Memory Layout - -| Field | Type | Size | Purpose | -| :--- | :--- | :---: | :--- | -| `Sum` | double | 8 bytes | Running sum S1 | -| `WSum` | double | 8 bytes | Weighted sum S2 | -| `PSum` | double | 8 bytes | Parabolic sum S3 | -| `LastInput` | double | 8 bytes | Previous input value | -| `LastValidValue` | double | 8 bytes | NaN substitution | -| `TickCount` | int | 4 bytes | Resync counter | -| **State total** | | **44 bytes** | Compiler-aligned | -| `_buffer` | RingBuffer | 24 + 8N | Sliding window | -| `_p_buffer` | RingBuffer | 24 + 8N | Bar correction backup | - -### Bar Correction Pattern - -```csharp -if (isNew) -{ - _p_state = _state; // Snapshot for rollback - _p_buffer.CopyFrom(_buffer); // Buffer snapshot -} -else -{ - _state = _p_state; // Restore previous state - _buffer.CopyFrom(_p_buffer); // Restore buffer -} -``` - -### Periodic Resync - -Triple cascading sums accumulate floating-point errors faster than simple running sums. The implementation resyncs every 1000 ticks: - -```csharp -if (_state.TickCount >= 1000) -{ - // Full O(N) recalculation to reset drift - RecalculateFromBuffer(); - _state = _state with { TickCount = 0 }; -} -``` - -### Common Pitfalls - -1. **Resync**: Because triple running sums are used, floating-point errors can accumulate faster than in a simple SMA. The implementation automatically resyncs every 1000 ticks to maintain precision. -2. **Sensitivity**: This indicator is very sensitive to the most recent bar. It can "repaint" visually if used on an open bar (though the math is consistent). diff --git a/lib/trends_FIR/pwma/Pwma.Quantower.Tests.cs b/lib/trends_FIR/pwma/tests/Pwma.Quantower.Tests.cs similarity index 100% rename from lib/trends_FIR/pwma/Pwma.Quantower.Tests.cs rename to lib/trends_FIR/pwma/tests/Pwma.Quantower.Tests.cs diff --git a/lib/trends_FIR/pwma/Pwma.Tests.cs b/lib/trends_FIR/pwma/tests/Pwma.Tests.cs similarity index 100% rename from lib/trends_FIR/pwma/Pwma.Tests.cs rename to lib/trends_FIR/pwma/tests/Pwma.Tests.cs diff --git a/lib/trends_FIR/pwma/Pwma.Validation.Tests.cs b/lib/trends_FIR/pwma/tests/Pwma.Validation.Tests.cs similarity index 100% rename from lib/trends_FIR/pwma/Pwma.Validation.Tests.cs rename to lib/trends_FIR/pwma/tests/Pwma.Validation.Tests.cs diff --git a/lib/trends_FIR/qrma/Qrma.Quantower.Tests.cs b/lib/trends_FIR/qrma/tests/Qrma.Quantower.Tests.cs similarity index 100% rename from lib/trends_FIR/qrma/Qrma.Quantower.Tests.cs rename to lib/trends_FIR/qrma/tests/Qrma.Quantower.Tests.cs diff --git a/lib/trends_FIR/qrma/Qrma.Tests.cs b/lib/trends_FIR/qrma/tests/Qrma.Tests.cs similarity index 100% rename from lib/trends_FIR/qrma/Qrma.Tests.cs rename to lib/trends_FIR/qrma/tests/Qrma.Tests.cs diff --git a/lib/trends_FIR/qrma/Qrma.Validation.Tests.cs b/lib/trends_FIR/qrma/tests/Qrma.Validation.Tests.cs similarity index 100% rename from lib/trends_FIR/qrma/Qrma.Validation.Tests.cs rename to lib/trends_FIR/qrma/tests/Qrma.Validation.Tests.cs diff --git a/lib/trends_FIR/rain/Rain.Quantower.Tests.cs b/lib/trends_FIR/rain/tests/Rain.Quantower.Tests.cs similarity index 100% rename from lib/trends_FIR/rain/Rain.Quantower.Tests.cs rename to lib/trends_FIR/rain/tests/Rain.Quantower.Tests.cs diff --git a/lib/trends_FIR/rain/Rain.Tests.cs b/lib/trends_FIR/rain/tests/Rain.Tests.cs similarity index 100% rename from lib/trends_FIR/rain/Rain.Tests.cs rename to lib/trends_FIR/rain/tests/Rain.Tests.cs diff --git a/lib/trends_FIR/rain/Rain.Validation.Tests.cs b/lib/trends_FIR/rain/tests/Rain.Validation.Tests.cs similarity index 100% rename from lib/trends_FIR/rain/Rain.Validation.Tests.cs rename to lib/trends_FIR/rain/tests/Rain.Validation.Tests.cs diff --git a/lib/trends_FIR/rwma/Rwma.Quantower.Tests.cs b/lib/trends_FIR/rwma/tests/Rwma.Quantower.Tests.cs similarity index 100% rename from lib/trends_FIR/rwma/Rwma.Quantower.Tests.cs rename to lib/trends_FIR/rwma/tests/Rwma.Quantower.Tests.cs diff --git a/lib/trends_FIR/rwma/Rwma.Tests.cs b/lib/trends_FIR/rwma/tests/Rwma.Tests.cs similarity index 100% rename from lib/trends_FIR/rwma/Rwma.Tests.cs rename to lib/trends_FIR/rwma/tests/Rwma.Tests.cs diff --git a/lib/trends_FIR/rwma/Rwma.Validation.Tests.cs b/lib/trends_FIR/rwma/tests/Rwma.Validation.Tests.cs similarity index 100% rename from lib/trends_FIR/rwma/Rwma.Validation.Tests.cs rename to lib/trends_FIR/rwma/tests/Rwma.Validation.Tests.cs diff --git a/lib/trends_FIR/sgma/Sgma.md b/lib/trends_FIR/sgma/Sgma.md index 4a86b7cb..e727d4fe 100644 --- a/lib/trends_FIR/sgma/Sgma.md +++ b/lib/trends_FIR/sgma/Sgma.md @@ -183,115 +183,6 @@ QuanTAlib validates SGMA against mathematical properties rather than external li | **Tulip** | ❌ | Not included. | | **Ooples** | ❌ | Not included. | -## C# Implementation Considerations - -QuanTAlib's SGMA uses precomputed weights with SIMD-accelerated dot products for efficient O(N) convolution. The implementation demonstrates several high-performance patterns: - -### Weight Precomputation - -```csharp -[MethodImpl(MethodImplOptions.AggressiveInlining)] -private static void ComputeWeights(Span weights, int period, int degree, out double invWeightSum) -{ - // Hardcoded weights for common periods (degree 2) - if (degree == 2 && period == 9) - { - weights[0] = -0.0281; weights[1] = 0.0337; // ... etc - invWeightSum = 1.0 / sum; - return; - } - // General computation for other cases -} -``` - -Weights are computed once at construction. The inverse weight sum (`invWeightSum`) replaces division with multiplication in the hot path. - -### Key Optimizations - -| Technique | Implementation | Benefit | -| :--- | :--- | :--- | -| **Precomputed weights** | `_weights[]` array + `_invWeightSum` | One-time cost at construction | -| **Hardcoded common cases** | Periods 5, 7, 9 with degree 2 | Bypasses general weight loop | -| **SIMD dot product** | `span.DotProduct(weights)` extension | AVX2-accelerated convolution | -| **Inverse multiplication** | `sum * invWeightSum` vs `sum / weightSum` | 15→3 cycles per division | -| **ArrayPool hybrid** | stackalloc ≤256, ArrayPool >256 | Zero allocation for typical periods | -| **FMA chains** | Warmup uses nested `FusedMultiplyAdd` | Hardware-accelerated accumulation | - -### SIMD Convolution - -The hot path uses split dot products to handle ring buffer wraparound: - -```csharp -int part1Len = period - head; -double sum = internalBuf.Slice(head, part1Len).DotProduct(weights.AsSpan(0, part1Len)) - + internalBuf[..head].DotProduct(weights.AsSpan(part1Len)); - -return sum * invWeightSum; -``` - -The `DotProduct` extension method uses AVX2/AVX-512 intrinsics when available. - -### FMA Chains in Warmup - -For warmup periods with known sizes, nested FMA reduces instruction count: - -```csharp -// Period 5, degree 2 warmup -double sum = Math.FusedMultiplyAdd(window[0], w0, - Math.FusedMultiplyAdd(window[1], w1, - Math.FusedMultiplyAdd(window[2], w2, - Math.FusedMultiplyAdd(window[3], w3, window[4] * w4)))); -``` - -### Memory Layout - -| Field | Type | Size | Purpose | -| :--- | :--- | :---: | :--- | -| `_period` | int | 4 bytes | Adjusted to odd | -| `_degree` | int | 4 bytes | Polynomial degree (0-4) | -| `_weights` | double[] | 8N bytes | Precomputed weight vector | -| `_invWeightSum` | double | 8 bytes | Cached 1/Σw | -| `_buffer` | RingBuffer | 24 + 8N | Sliding window | -| `_lastValidValue` | double | 8 bytes | NaN substitution | -| `_p_lastValidValue` | double | 8 bytes | Bar correction backup | -| **Instance total** | | **~56 + 16N bytes** | N = period | - -### Batch Processing Memory Strategy - -```csharp -// Threshold: stackalloc for small, ArrayPool for large -double[]? weightsArray = usePeriod > 256 ? ArrayPool.Shared.Rent(usePeriod) : null; -Span weights = usePeriod <= 256 - ? stackalloc double[usePeriod] - : weightsArray!.AsSpan(0, usePeriod); - -try -{ - // Process all bars -} -finally -{ - if (weightsArray != null) ArrayPool.Shared.Return(weightsArray); -} -``` - -### Bar Correction Pattern - -SGMA uses simple scalar state backup (no buffer duplication needed since RingBuffer handles `UpdateNewest`): - -```csharp -if (isNew) -{ - _p_lastValidValue = _lastValidValue; - _buffer.Add(val); -} -else -{ - _lastValidValue = _p_lastValidValue; - _buffer.UpdateNewest(val); -} -``` - ## Common Pitfalls 1. **Degree 0 Misuse**: If you want SMA, use SMA. Degree 0 SGMA is mathematically equivalent but wastes cycles on weight calculation. diff --git a/lib/trends_FIR/sgma/Sgma.Quantower.Tests.cs b/lib/trends_FIR/sgma/tests/Sgma.Quantower.Tests.cs similarity index 100% rename from lib/trends_FIR/sgma/Sgma.Quantower.Tests.cs rename to lib/trends_FIR/sgma/tests/Sgma.Quantower.Tests.cs diff --git a/lib/trends_FIR/sgma/Sgma.Tests.cs b/lib/trends_FIR/sgma/tests/Sgma.Tests.cs similarity index 100% rename from lib/trends_FIR/sgma/Sgma.Tests.cs rename to lib/trends_FIR/sgma/tests/Sgma.Tests.cs diff --git a/lib/trends_FIR/sgma/Sgma.Validation.Tests.cs b/lib/trends_FIR/sgma/tests/Sgma.Validation.Tests.cs similarity index 100% rename from lib/trends_FIR/sgma/Sgma.Validation.Tests.cs rename to lib/trends_FIR/sgma/tests/Sgma.Validation.Tests.cs diff --git a/lib/trends_FIR/sinema/Sinema.md b/lib/trends_FIR/sinema/Sinema.md index 8dd54e2e..023eb89e 100644 --- a/lib/trends_FIR/sinema/Sinema.md +++ b/lib/trends_FIR/sinema/Sinema.md @@ -113,115 +113,6 @@ Validation tests verify: - Output bounded by input range - Warmup weight adaptation -## C# Implementation Considerations - -QuanTAlib's SINEMA uses precomputed sine weights with O(N) convolution. The implementation demonstrates several high-performance patterns: - -### State Management - -```csharp -[StructLayout(LayoutKind.Auto)] -private record struct State(double LastValidValue); -private State _state; -private State _p_state; -``` - -Minimal state—only the last valid value needs tracking since weights are precomputed and buffer handles windowing. - -### Key Optimizations - -| Technique | Implementation | Benefit | -| :--- | :--- | :--- | -| **Precomputed weights** | `_weights[]` array at construction | Eliminates `sin()` calls in hot path | -| **Cached weight sum** | `_weightSum` stored at construction | Division uses constant denominator | -| **ArrayPool hybrid** | stackalloc ≤256, ArrayPool >256 | Zero allocation for typical periods | -| **RingBuffer** | `UpdateNewest` for bar correction | O(1) correction without buffer copy | -| **Adaptive warmup** | Recalculates weights for partial buffer | Valid output from first bar | - -### Constructor Weight Precomputation - -```csharp -public Sinema(int period) -{ - _weights = new double[period]; - double sum = 0; - for (int i = 0; i < period; i++) - { - _weights[i] = Math.Sin(Math.PI * (i + 1) / period); - sum += _weights[i]; - } - _weightSum = sum; -} -``` - -All `sin()` calls happen once at construction, not per-update. - -### Memory Layout - -| Field | Type | Size | Purpose | -| :--- | :--- | :---: | :--- | -| `_period` | int | 4 bytes | Window size | -| `_weights` | double[] | 8N bytes | Precomputed sine weights | -| `_weightSum` | double | 8 bytes | Cached Σw for normalization | -| `_buffer` | RingBuffer | 24 + 8N | Sliding window | -| `_state.LastValidValue` | double | 8 bytes | NaN substitution | -| `_p_state.LastValidValue` | double | 8 bytes | Bar correction backup | -| **Instance total** | | **~52 + 16N bytes** | N = period | - -### Bar Correction Pattern - -```csharp -if (isNew) -{ - _p_state = _state; - _buffer.Add(val); -} -else -{ - _state = _p_state; - _buffer.UpdateNewest(val); -} -``` - -Simple state backup; RingBuffer's `UpdateNewest` handles in-place modification. - -### Batch Processing Memory Strategy - -```csharp -const int StackAllocThreshold = 256; -double[]? rentedBuffer = period > StackAllocThreshold ? ArrayPool.Shared.Rent(period) : null; -double[]? rentedWeights = period > StackAllocThreshold ? ArrayPool.Shared.Rent(period) : null; - -Span buffer = rentedBuffer != null - ? rentedBuffer.AsSpan(0, period) - : stackalloc double[period]; - -try { /* process */ } -finally -{ - if (rentedBuffer != null) ArrayPool.Shared.Return(rentedBuffer); - if (rentedWeights != null) ArrayPool.Shared.Return(rentedWeights); -} -``` - -### Warmup Weight Adaptation - -During warmup, weights are dynamically recalculated for the partial buffer: - -```csharp -if (count < _period) -{ - for (int j = 0; j < count; j++) - { - double w = Math.Sin(Math.PI * (j + 1) / count); - sum += buffer[j] * w; - weightSum += w; - } -} -``` - -This produces valid, smooth output from bar 1 without waiting for a full window. - ## Common Pitfalls 1. **O(N) Complexity**: Unlike SMA's O(1) running sum, SINEMA requires O(N) operations per bar. For very long periods (>500), consider whether the smoothness benefits justify the cost. diff --git a/lib/trends_FIR/sinema/Sinema.Quantower.Tests.cs b/lib/trends_FIR/sinema/tests/Sinema.Quantower.Tests.cs similarity index 100% rename from lib/trends_FIR/sinema/Sinema.Quantower.Tests.cs rename to lib/trends_FIR/sinema/tests/Sinema.Quantower.Tests.cs diff --git a/lib/trends_FIR/sinema/Sinema.Tests.cs b/lib/trends_FIR/sinema/tests/Sinema.Tests.cs similarity index 100% rename from lib/trends_FIR/sinema/Sinema.Tests.cs rename to lib/trends_FIR/sinema/tests/Sinema.Tests.cs diff --git a/lib/trends_FIR/sinema/Sinema.Validation.Tests.cs b/lib/trends_FIR/sinema/tests/Sinema.Validation.Tests.cs similarity index 100% rename from lib/trends_FIR/sinema/Sinema.Validation.Tests.cs rename to lib/trends_FIR/sinema/tests/Sinema.Validation.Tests.cs diff --git a/lib/trends_FIR/sma/Sma.md b/lib/trends_FIR/sma/Sma.md index b507b2b7..5f0dc6b4 100644 --- a/lib/trends_FIR/sma/Sma.md +++ b/lib/trends_FIR/sma/Sma.md @@ -116,91 +116,3 @@ For 512 bars: | **Skender** | ✅ | Matches `GetSma` exactly. | | **Tulip** | ✅ | Matches `sma` exactly. | | **Ooples** | ✅ | Matches `CalculateSimpleMovingAverage`. | - -## C# Implementation Considerations - -### RingBuffer for O(1) Running Sum - -The implementation maintains a `RingBuffer` of the most recent $N$ values alongside a running `Sum`. On each update, the oldest value is subtracted and the newest added—eliminating the need to iterate over the entire window: - -```csharp -Sum = Math.FusedMultiplyAdd(-_buffer[^1], 1, Sum + p); -_buffer.Add(p, isNew); -``` - -Using `FusedMultiplyAdd` for the combined subtraction/addition improves numerical stability compared to separate operations. - -### State Record Struct - -Minimal state is captured in a `record struct` for efficient bar correction: - -```csharp -private record struct State(double Sum, double LastValidValue, int TickCount); -``` - -When `isNew=false`, the implementation restores `_p_state` to revert any partial calculation—enabling accurate bar correction when the same timestamp updates multiple times. - -### Periodic Resync for Drift Correction - -Floating-point drift accumulates over millions of additions/subtractions. The implementation resyncs every 1000 ticks: - -```csharp -if (_state.TickCount >= ResyncPeriod) -{ - _state = _state with { Sum = _buffer.Span.Sum(), TickCount = 0 }; -} -``` - -This bounds cumulative error to within `1e-9` of true mean regardless of stream length. - -### Multi-Architecture SIMD Implementation - -The static `Calculate` method dispatches to architecture-specific implementations: - -```csharp -if (Avx512F.IsSupported) CalculateAvx512Core(source, output, period); -else if (Avx2.IsSupported) CalculateAvx2Core(source, output, period); -else if (AdvSimd.Arm64.IsSupported) CalculateNeonCore(source, output, period); -else CalculateScalarCore(source, output, period); -``` - -- **AVX-512**: Processes 8 doubles simultaneously with 512-bit vectors -- **AVX2**: Processes 4 doubles with 256-bit vectors -- **NEON (ARM64)**: Processes 2 doubles with 128-bit vectors -- **Scalar fallback**: Portable loop for unsupported architectures - -### Prefix-Sum Vectorization - -For batch processing, the SIMD paths use a prefix-sum technique that enables parallel computation of running sums. The initial window sum is computed with vectorized horizontal addition, then subsequent values use the optimized running-sum pattern. - -### ArrayPool for Memory Efficiency - -Large period buffers are rented from `ArrayPool` rather than allocated, reducing GC pressure during batch operations. Combined with `stackalloc` for small intermediate buffers, this achieves zero-allocation in hot paths. - -### NaN Handling with Last-Valid Substitution - -Non-finite inputs are replaced with the last valid value stored in state: - -```csharp -p = double.IsFinite(p) ? p : _state.LastValidValue; -``` - -This prevents NaN propagation through the running sum without requiring expensive validation on every buffer access. - -### Memory Layout - -| Component | Size | Purpose | -| :--- | :--- | :--- | -| `_buffer` (RingBuffer) | 32 + 8×period bytes | Sliding window history | -| `_state` | ~24 bytes | Sum, LastValidValue, TickCount | -| `_p_state` | ~24 bytes | Previous state for rollback | -| Scalars | ~16 bytes | Period, reciprocal | -| **Total** | **~96 + 8N bytes** | Per-instance footprint | - -For SMA(200), total memory is approximately 1.7 KB per instance. - -### Common Pitfalls - -1. **Lag**: SMA has the most lag of all moving averages (Lag $\approx N/2$). -2. **Drop-off Effect**: An old, large outlier dropping out of the window causes the SMA to jump, even if the current price is flat. This "Barker effect" is why EMAs are often preferred. -3. **NaN Handling**: A single `NaN` in the history window corrupts the entire SMA. QuanTAlib handles this by substituting the last valid value. diff --git a/lib/trends_FIR/sma/Sma.Quantower.Tests.cs b/lib/trends_FIR/sma/tests/Sma.Quantower.Tests.cs similarity index 100% rename from lib/trends_FIR/sma/Sma.Quantower.Tests.cs rename to lib/trends_FIR/sma/tests/Sma.Quantower.Tests.cs diff --git a/lib/trends_FIR/sma/Sma.Tests.cs b/lib/trends_FIR/sma/tests/Sma.Tests.cs similarity index 100% rename from lib/trends_FIR/sma/Sma.Tests.cs rename to lib/trends_FIR/sma/tests/Sma.Tests.cs diff --git a/lib/trends_FIR/sma/Sma.Tolerance.Tests.cs b/lib/trends_FIR/sma/tests/Sma.Tolerance.Tests.cs similarity index 100% rename from lib/trends_FIR/sma/Sma.Tolerance.Tests.cs rename to lib/trends_FIR/sma/tests/Sma.Tolerance.Tests.cs diff --git a/lib/trends_FIR/sma/Sma.Validation.Tests.cs b/lib/trends_FIR/sma/tests/Sma.Validation.Tests.cs similarity index 100% rename from lib/trends_FIR/sma/Sma.Validation.Tests.cs rename to lib/trends_FIR/sma/tests/Sma.Validation.Tests.cs diff --git a/lib/trends_FIR/sma/Sma.ZeroDiv.Tests.cs b/lib/trends_FIR/sma/tests/Sma.ZeroDiv.Tests.cs similarity index 100% rename from lib/trends_FIR/sma/Sma.ZeroDiv.Tests.cs rename to lib/trends_FIR/sma/tests/Sma.ZeroDiv.Tests.cs diff --git a/lib/trends_FIR/sp15/Sp15.Quantower.Tests.cs b/lib/trends_FIR/sp15/tests/Sp15.Quantower.Tests.cs similarity index 100% rename from lib/trends_FIR/sp15/Sp15.Quantower.Tests.cs rename to lib/trends_FIR/sp15/tests/Sp15.Quantower.Tests.cs diff --git a/lib/trends_FIR/sp15/Sp15.Tests.cs b/lib/trends_FIR/sp15/tests/Sp15.Tests.cs similarity index 100% rename from lib/trends_FIR/sp15/Sp15.Tests.cs rename to lib/trends_FIR/sp15/tests/Sp15.Tests.cs diff --git a/lib/trends_FIR/sp15/Sp15.Validation.Tests.cs b/lib/trends_FIR/sp15/tests/Sp15.Validation.Tests.cs similarity index 100% rename from lib/trends_FIR/sp15/Sp15.Validation.Tests.cs rename to lib/trends_FIR/sp15/tests/Sp15.Validation.Tests.cs diff --git a/lib/trends_FIR/swma/Swma.Quantower.Tests.cs b/lib/trends_FIR/swma/tests/Swma.Quantower.Tests.cs similarity index 100% rename from lib/trends_FIR/swma/Swma.Quantower.Tests.cs rename to lib/trends_FIR/swma/tests/Swma.Quantower.Tests.cs diff --git a/lib/trends_FIR/swma/Swma.Tests.cs b/lib/trends_FIR/swma/tests/Swma.Tests.cs similarity index 100% rename from lib/trends_FIR/swma/Swma.Tests.cs rename to lib/trends_FIR/swma/tests/Swma.Tests.cs diff --git a/lib/trends_FIR/swma/Swma.Validation.Tests.cs b/lib/trends_FIR/swma/tests/Swma.Validation.Tests.cs similarity index 100% rename from lib/trends_FIR/swma/Swma.Validation.Tests.cs rename to lib/trends_FIR/swma/tests/Swma.Validation.Tests.cs diff --git a/lib/trends_FIR/trima/Trima.md b/lib/trends_FIR/trima/Trima.md index af3c6a1f..1cb87432 100644 --- a/lib/trends_FIR/trima/Trima.md +++ b/lib/trends_FIR/trima/Trima.md @@ -91,111 +91,3 @@ Each SMA component benefits from SIMD prefix-sum optimization: | **Skender** | ✅ | Matches composite `SMA(SMA)` logic. | | **Tulip** | ✅ | Matches `trima` exactly. | | **Ooples** | N/A | Not implemented. | - -## C# Implementation Considerations - -QuanTAlib's TRIMA uses cascaded SMA composition, achieving O(1) streaming updates by leveraging the O(1) nature of each internal SMA. The implementation demonstrates clean indicator composition: - -### Composition Architecture - -```csharp -[SkipLocalsInit] -public sealed class Trima : AbstractBase -{ - private readonly Sma _sma1; - private readonly Sma _sma2; - - public Trima(int period) - { - int p1 = (period + 1) / 2; - int p2 = period / 2 + 1; - - _sma1 = new Sma(p1); - _sma2 = new Sma(p2); - } -} -``` - -TRIMA delegates all complexity to its internal SMA instances. Each SMA maintains its own O(1) running sum, so the cascade is also O(1). - -### Key Optimizations - -| Technique | Implementation | Benefit | -| :--- | :--- | :--- | -| **SMA delegation** | Two internal `Sma` instances | O(1) streaming via running sums | -| **Zero state** | No additional fields beyond SMAs | Minimal memory footprint | -| **Inline cascade** | `_sma2.Update(_sma1.Update(input))` | No intermediate allocation | -| **ArrayPool** | Batch uses rented buffer for SMA1 output | Zero allocation in batch mode | -| **Warmup composition** | `WarmupPeriod = p1 + p2 - 1` | Correct cascaded warmup | - -### Streaming Update - -```csharp -[MethodImpl(MethodImplOptions.AggressiveInlining)] -public override TValue Update(TValue input, bool isNew = true) -{ - _isNew = isNew; - TValue v1 = _sma1.Update(input, isNew); - TValue v2 = _sma2.Update(v1, isNew); - - Last = v2; - PubEvent(Last, isNew); - return Last; -} -``` - -The `isNew` flag propagates through both SMAs, enabling bar correction at both levels. - -### Memory Layout - -| Field | Type | Size | Purpose | -| :--- | :--- | :---: | :--- | -| `_period` | int | 4 bytes | Original period | -| `_sma1` | Sma | ~48 + 8×P₁ bytes | First smoothing stage | -| `_sma2` | Sma | ~48 + 8×P₂ bytes | Second smoothing stage | -| `_handler` | delegate | 8 bytes | Event handler reference | -| `_isNew` | bool | 1 byte | Current bar state | -| **Instance total** | | **~110 + 8N bytes** | N = period | - -### Batch Processing - -```csharp -public static void Batch(ReadOnlySpan source, Span output, int period) -{ - int p1 = (period + 1) / 2; - int p2 = period / 2 + 1; - - double[] tempArray = ArrayPool.Shared.Rent(source.Length); - Span tempSpan = tempArray.AsSpan(0, source.Length); - - try - { - Sma.Batch(source, tempSpan, p1); // First SMA pass - Sma.Batch(tempSpan, output, p2); // Second SMA pass - } - finally - { - ArrayPool.Shared.Return(tempArray); - } -} -``` - -Uses ArrayPool for the intermediate buffer to avoid heap allocation per batch. - -### Bar Correction Propagation - -The `isNew` flag propagates through both internal SMAs: - -```csharp -// isNew=false triggers rollback in BOTH SMAs -TValue v1 = _sma1.Update(input, isNew); // SMA1 rolls back its running sum -TValue v2 = _sma2.Update(v1, isNew); // SMA2 rolls back based on corrected SMA1 output -``` - -This ensures consistent bar correction across the entire cascade. - -### Common Pitfalls - -1. **Lag**: TRIMA has more lag than SMA, EMA, or WMA. It is a lagging indicator, not a leading one. -2. **Signal Generation**: Due to its lag, TRIMA is poor for crossover signals. It is best used for visual trend identification or as a baseline for envelopes (e.g., TMA Bands). -3. **Even/Odd Periods**: The exact calculation of $P_1$ and $P_2$ differs slightly between implementations for even periods. QuanTAlib matches the standard definition used by TA-Lib. diff --git a/lib/trends_FIR/trima/Trima.Quantower.Tests.cs b/lib/trends_FIR/trima/tests/Trima.Quantower.Tests.cs similarity index 100% rename from lib/trends_FIR/trima/Trima.Quantower.Tests.cs rename to lib/trends_FIR/trima/tests/Trima.Quantower.Tests.cs diff --git a/lib/trends_FIR/trima/Trima.Tests.cs b/lib/trends_FIR/trima/tests/Trima.Tests.cs similarity index 100% rename from lib/trends_FIR/trima/Trima.Tests.cs rename to lib/trends_FIR/trima/tests/Trima.Tests.cs diff --git a/lib/trends_FIR/trima/Trima.Tolerance.Tests.cs b/lib/trends_FIR/trima/tests/Trima.Tolerance.Tests.cs similarity index 100% rename from lib/trends_FIR/trima/Trima.Tolerance.Tests.cs rename to lib/trends_FIR/trima/tests/Trima.Tolerance.Tests.cs diff --git a/lib/trends_FIR/trima/Trima.Validation.Tests.cs b/lib/trends_FIR/trima/tests/Trima.Validation.Tests.cs similarity index 100% rename from lib/trends_FIR/trima/Trima.Validation.Tests.cs rename to lib/trends_FIR/trima/tests/Trima.Validation.Tests.cs diff --git a/lib/trends_FIR/tsf/Tsf.Quantower.Tests.cs b/lib/trends_FIR/tsf/tests/Tsf.Quantower.Tests.cs similarity index 100% rename from lib/trends_FIR/tsf/Tsf.Quantower.Tests.cs rename to lib/trends_FIR/tsf/tests/Tsf.Quantower.Tests.cs diff --git a/lib/trends_FIR/tsf/Tsf.Tests.cs b/lib/trends_FIR/tsf/tests/Tsf.Tests.cs similarity index 100% rename from lib/trends_FIR/tsf/Tsf.Tests.cs rename to lib/trends_FIR/tsf/tests/Tsf.Tests.cs diff --git a/lib/trends_FIR/tsf/Tsf.Validation.Tests.cs b/lib/trends_FIR/tsf/tests/Tsf.Validation.Tests.cs similarity index 100% rename from lib/trends_FIR/tsf/Tsf.Validation.Tests.cs rename to lib/trends_FIR/tsf/tests/Tsf.Validation.Tests.cs diff --git a/lib/trends_FIR/tukey_w/Tukey_w.Quantower.Tests.cs b/lib/trends_FIR/tukey_w/tests/Tukey_w.Quantower.Tests.cs similarity index 100% rename from lib/trends_FIR/tukey_w/Tukey_w.Quantower.Tests.cs rename to lib/trends_FIR/tukey_w/tests/Tukey_w.Quantower.Tests.cs diff --git a/lib/trends_FIR/tukey_w/Tukey_w.Tests.cs b/lib/trends_FIR/tukey_w/tests/Tukey_w.Tests.cs similarity index 100% rename from lib/trends_FIR/tukey_w/Tukey_w.Tests.cs rename to lib/trends_FIR/tukey_w/tests/Tukey_w.Tests.cs diff --git a/lib/trends_FIR/tukey_w/Tukey_w.Validation.Tests.cs b/lib/trends_FIR/tukey_w/tests/Tukey_w.Validation.Tests.cs similarity index 100% rename from lib/trends_FIR/tukey_w/Tukey_w.Validation.Tests.cs rename to lib/trends_FIR/tukey_w/tests/Tukey_w.Validation.Tests.cs diff --git a/lib/trends_FIR/wma/Wma.md b/lib/trends_FIR/wma/Wma.md index b6f5652e..fd31c5ce 100644 --- a/lib/trends_FIR/wma/Wma.md +++ b/lib/trends_FIR/wma/Wma.md @@ -108,150 +108,3 @@ The batch path achieves near-linear scaling for large datasets. | **Skender** | ✅ | Matches `GetWma` exactly. | | **Tulip** | ✅ | Matches `wma` exactly. | | **Ooples** | ✅ | Matches `CalculateWeightedMovingAverage`. | - -## C# Implementation Considerations - -### Dual Running-Sum O(1) Algorithm - -The implementation maintains both a simple `Sum` and a weighted `WSum` for O(1) updates. The elegant recurrence relation avoids recalculating weights: - -```csharp -double oldSum = _state.Sum; -double oldest = _buffer.Oldest; -_state.Sum = Math.FusedMultiplyAdd(-1.0, oldest, _state.Sum + val); -_state.WSum = Math.FusedMultiplyAdd(-1.0, oldSum, _state.WSum + _period * val); -``` - -Using `FusedMultiplyAdd` for combined add-subtract operations improves numerical precision. - -### State Record Struct with Auto Layout - -State is captured for efficient bar correction: - -```csharp -[StructLayout(LayoutKind.Auto)] -private record struct State(double Sum, double WSum, double LastInput, - double LastValidValue, int TickCount, bool HasSeenValidData); -``` - -The `LayoutKind.Auto` allows the JIT to optimize field arrangement for cache efficiency. - -### Periodic Resync for Drift Correction - -With dual running sums, drift accumulates faster than SMA. The implementation resyncs every 10,000 ticks: - -```csharp -if (needResync || (isNaN && double.IsFinite(val))) -{ - double recalcSum = 0; - double recalcWsum = 0; - int weight = 1; - foreach (double item in _buffer) - { - recalcSum += item; - recalcWsum = Math.FusedMultiplyAdd(weight, item, recalcWsum); - weight++; - } - _state.Sum = recalcSum; - _state.WSum = recalcWsum; -} -``` - -### Multi-Architecture SIMD with Prefix Sums - -The static `Batch` method dispatches to architecture-specific implementations: - -```csharp -if (Avx512F.IsSupported && len >= simdThreshold && !source.ContainsNonFinite()) - CalculateAvx512Core(source, output, period); -else if (Avx2.IsSupported && len >= simdThreshold && !source.ContainsNonFinite()) - CalculateSimdCore(source, output, period); -else if (AdvSimd.Arm64.IsSupported && len >= simdThreshold && !source.ContainsNonFinite()) - CalculateNeonCore(source, output, period); -else - CalculateScalarCore(source, output, period); -``` - -### AVX-512 Vectorized Prefix Sums - -The AVX-512 path uses pre-computed shuffle indices and masks for efficient prefix-sum computation: - -```csharp -private static readonly Vector512 V512Idx1 = Vector512.Create(0L, 0, 1, 2, 3, 4, 5, 6); -private static readonly Vector512 V512Mask1 = Vector512.Create(0.0, 1, 1, 1, 1, 1, 1, 1); -``` - -The weighted sum update uses `FusedMultiplySubtract` for the formula $U_i = N \times P_i - S_{i-1}$: - -```csharp -var vU = Avx512F.FusedMultiplySubtract(vPeriod, vNew, vSumsShifted); -``` - -### AVX2 Loop Unrolling - -The AVX2 path processes 8 elements per iteration (2 vectors of 4 doubles) for improved throughput: - -```csharp -for (; idx <= unrolledSync; idx += 2 * vectorWidth) -{ - var vNew1 = Vector256.LoadUnsafe(ref Unsafe.Add(ref srcRef, idx)); - var vNew2 = Vector256.LoadUnsafe(ref Unsafe.Add(ref srcRef, idx + vectorWidth)); - // Process both vectors simultaneously -} -``` - -This maximizes instruction-level parallelism by overlapping independent operations. - -### NEON ARM64 Implementation - -The ARM64 NEON path processes 2 doubles at a time with explicit scalar prefix-sum accumulation: - -```csharp -double u0 = Math.FusedMultiplyAdd(period, vNew.GetElement(0), -sumState); -double u1 = Math.FusedMultiplyAdd(period, vNew.GetElement(1), -ps0); -``` - -### NaN Handling with Fallback Tracking - -Non-finite inputs are replaced with the last valid value, with explicit tracking for first-value edge case: - -```csharp -public double DefaultLastValidValue { get; set; } = double.NaN; - -private double GetValidValue(double input) -{ - if (double.IsFinite(input)) - { - _state.LastValidValue = input; - _state.HasSeenValidData = true; - return input; - } - return _state.HasSeenValidData ? _state.LastValidValue : DefaultLastValidValue; -} -``` - -### Stackalloc for Scalar Batch Buffer - -The scalar path uses `stackalloc` for small periods to avoid heap allocation: - -```csharp -Span buffer = period <= 512 ? stackalloc double[period] : new double[period]; -``` - -### Memory Layout - -| Component | Size | Purpose | -| :--- | :--- | :--- | -| `_buffer` (RingBuffer) | 32 + 8×period bytes | Sliding window history | -| `_state` | ~48 bytes | Sum, WSum, LastInput, LastValidValue, TickCount, flags | -| `_pState` | ~48 bytes | Previous state for rollback | -| Scalars | ~24 bytes | Period, divisor, source reference | -| **Total** | **~152 + 8N bytes** | Per-instance footprint | - -For WMA(200), total memory is approximately 1.75 KB per instance. - -### Common Pitfalls - -1. **Drift**: Like SMA, the O(1) algorithm is susceptible to floating-point drift. QuanTAlib resets the sums every 10,000 ticks to guarantee accuracy. -2. **Aggressiveness**: WMA reacts faster than SMA but can be "twitchy." It is often used as a component in other indicators (e.g., HMA) rather than a standalone trend filter. -3. **Weights**: Users sometimes confuse WMA (linear weights) with EMA (exponential weights) or VWAP (volume weights). diff --git a/lib/trends_FIR/wma/Wma.Coverage.Tests.cs b/lib/trends_FIR/wma/tests/Wma.Coverage.Tests.cs similarity index 100% rename from lib/trends_FIR/wma/Wma.Coverage.Tests.cs rename to lib/trends_FIR/wma/tests/Wma.Coverage.Tests.cs diff --git a/lib/trends_FIR/wma/Wma.Quantower.Tests.cs b/lib/trends_FIR/wma/tests/Wma.Quantower.Tests.cs similarity index 100% rename from lib/trends_FIR/wma/Wma.Quantower.Tests.cs rename to lib/trends_FIR/wma/tests/Wma.Quantower.Tests.cs diff --git a/lib/trends_FIR/wma/Wma.Tests.cs b/lib/trends_FIR/wma/tests/Wma.Tests.cs similarity index 100% rename from lib/trends_FIR/wma/Wma.Tests.cs rename to lib/trends_FIR/wma/tests/Wma.Tests.cs diff --git a/lib/trends_FIR/wma/Wma.Validation.Tests.cs b/lib/trends_FIR/wma/tests/Wma.Validation.Tests.cs similarity index 100% rename from lib/trends_FIR/wma/Wma.Validation.Tests.cs rename to lib/trends_FIR/wma/tests/Wma.Validation.Tests.cs diff --git a/lib/trends_IIR/adxvma/Adxvma.Quantower.Tests.cs b/lib/trends_IIR/adxvma/tests/Adxvma.Quantower.Tests.cs similarity index 100% rename from lib/trends_IIR/adxvma/Adxvma.Quantower.Tests.cs rename to lib/trends_IIR/adxvma/tests/Adxvma.Quantower.Tests.cs diff --git a/lib/trends_IIR/adxvma/Adxvma.Tests.cs b/lib/trends_IIR/adxvma/tests/Adxvma.Tests.cs similarity index 100% rename from lib/trends_IIR/adxvma/Adxvma.Tests.cs rename to lib/trends_IIR/adxvma/tests/Adxvma.Tests.cs diff --git a/lib/trends_IIR/adxvma/Adxvma.Validation.Tests.cs b/lib/trends_IIR/adxvma/tests/Adxvma.Validation.Tests.cs similarity index 100% rename from lib/trends_IIR/adxvma/Adxvma.Validation.Tests.cs rename to lib/trends_IIR/adxvma/tests/Adxvma.Validation.Tests.cs diff --git a/lib/trends_IIR/ahrens/Ahrens.Quantower.Tests.cs b/lib/trends_IIR/ahrens/tests/Ahrens.Quantower.Tests.cs similarity index 100% rename from lib/trends_IIR/ahrens/Ahrens.Quantower.Tests.cs rename to lib/trends_IIR/ahrens/tests/Ahrens.Quantower.Tests.cs diff --git a/lib/trends_IIR/ahrens/Ahrens.Tests.cs b/lib/trends_IIR/ahrens/tests/Ahrens.Tests.cs similarity index 100% rename from lib/trends_IIR/ahrens/Ahrens.Tests.cs rename to lib/trends_IIR/ahrens/tests/Ahrens.Tests.cs diff --git a/lib/trends_IIR/ahrens/Ahrens.Validation.Tests.cs b/lib/trends_IIR/ahrens/tests/Ahrens.Validation.Tests.cs similarity index 100% rename from lib/trends_IIR/ahrens/Ahrens.Validation.Tests.cs rename to lib/trends_IIR/ahrens/tests/Ahrens.Validation.Tests.cs diff --git a/lib/trends_IIR/coral/Coral.Quantower.Tests.cs b/lib/trends_IIR/coral/tests/Coral.Quantower.Tests.cs similarity index 100% rename from lib/trends_IIR/coral/Coral.Quantower.Tests.cs rename to lib/trends_IIR/coral/tests/Coral.Quantower.Tests.cs diff --git a/lib/trends_IIR/coral/Coral.Tests.cs b/lib/trends_IIR/coral/tests/Coral.Tests.cs similarity index 100% rename from lib/trends_IIR/coral/Coral.Tests.cs rename to lib/trends_IIR/coral/tests/Coral.Tests.cs diff --git a/lib/trends_IIR/coral/Coral.Validation.Tests.cs b/lib/trends_IIR/coral/tests/Coral.Validation.Tests.cs similarity index 100% rename from lib/trends_IIR/coral/Coral.Validation.Tests.cs rename to lib/trends_IIR/coral/tests/Coral.Validation.Tests.cs diff --git a/lib/trends_IIR/decycler/Decycler.md b/lib/trends_IIR/decycler/Decycler.md index cc800b92..e8de3908 100644 --- a/lib/trends_IIR/decycler/Decycler.md +++ b/lib/trends_IIR/decycler/Decycler.md @@ -240,54 +240,6 @@ var dec = new Decycler(source, period: 60); var (results, indicator) = Decycler.Calculate(series, period: 60); ``` -## C# Implementation Considerations - -### State Record Struct with Auto Layout - -All IIR filter state is packed into a `record struct` with `LayoutKind.Auto` for compiler-optimized field ordering: - -```csharp -[StructLayout(LayoutKind.Auto)] -private record struct State -{ - public double Hp; - public double Hp1; - public double Src1; - public double Src2; - public bool IsInitialized; -} -``` - -Five fields, ~40 bytes. Minimal footprint per instance. - -### FusedMultiplyAdd for IIR Recurrence - -The HP recurrence uses nested `Math.FusedMultiplyAdd` calls to minimize rounding error and exploit hardware FMA instructions: - -```csharp -double hp = Math.FusedMultiplyAdd(_a1, src - 2.0 * _state.Src1 + _state.Src2, - Math.FusedMultiplyAdd(_b1, _state.Hp, _c1 * _state.Hp1)); -``` - -### Precomputed Coefficients - -The trigonometric operations ($\cos$, $\sin$) execute once in the constructor. The hot path uses only the three precomputed coefficients `_a1`, `_b1`, `_c1`. - -### Bar Correction via State Snapshots - -The `_state` / `_p_state` pattern enables bar correction: - -```csharp -if (isNew) { _p_state = _state; } -else { _state = _p_state; } -``` - -### Memory Layout - -- **State struct**: ~40 bytes (4 doubles + 1 bool + padding) -- **Precomputed coefficients**: 24 bytes (3 doubles) -- **Total per instance**: ~120 bytes including base class overhead - ## References - Ehlers, J. F. (2015). "Decyclers." *Technical Analysis of Stocks & Commodities*, September 2015. diff --git a/lib/trends_IIR/decycler/Decycler.Quantower.Tests.cs b/lib/trends_IIR/decycler/tests/Decycler.Quantower.Tests.cs similarity index 100% rename from lib/trends_IIR/decycler/Decycler.Quantower.Tests.cs rename to lib/trends_IIR/decycler/tests/Decycler.Quantower.Tests.cs diff --git a/lib/trends_IIR/decycler/Decycler.Tests.cs b/lib/trends_IIR/decycler/tests/Decycler.Tests.cs similarity index 100% rename from lib/trends_IIR/decycler/Decycler.Tests.cs rename to lib/trends_IIR/decycler/tests/Decycler.Tests.cs diff --git a/lib/trends_IIR/decycler/Decycler.Validation.Tests.cs b/lib/trends_IIR/decycler/tests/Decycler.Validation.Tests.cs similarity index 100% rename from lib/trends_IIR/decycler/Decycler.Validation.Tests.cs rename to lib/trends_IIR/decycler/tests/Decycler.Validation.Tests.cs diff --git a/lib/trends_IIR/dema/Dema.md b/lib/trends_IIR/dema/Dema.md index 7874fe36..30952136 100644 --- a/lib/trends_IIR/dema/Dema.md +++ b/lib/trends_IIR/dema/Dema.md @@ -216,106 +216,6 @@ var dema = new Dema(source, period); | **Tulip** | ✅ | Matches `dema` (tolerance: 1e-9) | | **Ooples** | ✅ | Matches `2*EMA - EMA(EMA)` formula | -## C# Implementation Considerations - -QuanTAlib's DEMA uses cascaded EMA instances with bias compensation and extensive FMA optimization. The implementation demonstrates several high-performance patterns: - -### State Management - -```csharp -[StructLayout(LayoutKind.Auto)] -private record struct EmaState(double Ema, double E, bool IsHot, bool IsCompensated) -{ - public static EmaState New() => new() { Ema = 0, E = 1.0, IsHot = false, IsCompensated = false }; -} - -private EmaState _state1 = EmaState.New(); -private EmaState _state2 = EmaState.New(); -private EmaState _p_state1 = EmaState.New(); // Bar correction backup -private EmaState _p_state2 = EmaState.New(); // Bar correction backup -``` - -Each EMA stage has its own state with bias compensation tracking. Four state copies enable bar correction across both stages. - -### Key Optimizations - -| Technique | Implementation | Benefit | -| :--- | :--- | :--- | -| **Precomputed constants** | `_alpha = 2.0/(period+1)`, `_decay = 1-_alpha` | Eliminates division in hot path | -| **FMA in EMA update** | `FusedMultiplyAdd(ema, decay, alpha * input)` | Hardware-accelerated smoothing | -| **FMA in combiner** | `FusedMultiplyAdd(2.0, e1, -e2)` | Single instruction for DEMA formula | -| **Bias compensation** | Tracks convergence factor `E` | Accurate warmup values | -| **Auto-transition** | `IsCompensated` flag skips division | Steady-state optimization | - -### FMA Usage - -```csharp -// EMA smoothing step (IIR pattern) -state.Ema = Math.FusedMultiplyAdd(state.Ema, decay, alpha * input); - -// Final DEMA combiner: 2*e1 - e2 → FMA(2.0, e1, -e2) -double result = Math.FusedMultiplyAdd(2.0, e1, -e2); -``` - -### Bias Compensation Logic - -```csharp -[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)] -private static double Compute(double input, double alpha, double decay, ref EmaState state) -{ - state.Ema = Math.FusedMultiplyAdd(state.Ema, decay, alpha * input); - - if (!state.IsCompensated) - { - state.E *= decay; // Bias factor decays each tick - - if (!state.IsHot && state.E <= 0.05) // 95% coverage - state.IsHot = true; - - if (state.E <= 1e-10) // Full convergence - { - state.IsCompensated = true; - return state.Ema; - } - return state.Ema / (1.0 - state.E); // Bias-corrected - } - return state.Ema; // No compensation needed -} -``` - -### Memory Layout - -| Field | Type | Size | Purpose | -| :--- | :--- | :---: | :--- | -| `_alpha` | double | 8 bytes | EMA smoothing factor | -| `_decay` | double | 8 bytes | 1 - alpha (precomputed) | -| `_state1` | EmaState | 20 bytes | First EMA stage state | -| `_state2` | EmaState | 20 bytes | Second EMA stage state | -| `_p_state1` | EmaState | 20 bytes | Bar correction backup | -| `_p_state2` | EmaState | 20 bytes | Bar correction backup | -| `_lastValidValue` | double | 8 bytes | NaN substitution | -| `_p_lastValidValue` | double | 8 bytes | Bar correction backup | -| **Instance total** | | **~112 bytes** | No period-dependent allocations | - -### Bar Correction Pattern - -```csharp -if (isNew) -{ - _p_state1 = _state1; - _p_state2 = _state2; - _p_lastValidValue = _lastValidValue; -} -else -{ - _state1 = _p_state1; - _state2 = _p_state2; - _lastValidValue = _p_lastValidValue; -} -``` - -Both EMA states are rolled back atomically for consistent correction. - ## Reference Calculation Table | Period | Price Sequence | EMA₁ | EMA₂ | DEMA | Notes | diff --git a/lib/trends_IIR/dema/Dema.Quantower.Tests.cs b/lib/trends_IIR/dema/tests/Dema.Quantower.Tests.cs similarity index 100% rename from lib/trends_IIR/dema/Dema.Quantower.Tests.cs rename to lib/trends_IIR/dema/tests/Dema.Quantower.Tests.cs diff --git a/lib/trends_IIR/dema/Dema.Tests.cs b/lib/trends_IIR/dema/tests/Dema.Tests.cs similarity index 100% rename from lib/trends_IIR/dema/Dema.Tests.cs rename to lib/trends_IIR/dema/tests/Dema.Tests.cs diff --git a/lib/trends_IIR/dema/Dema.Validation.Tests.cs b/lib/trends_IIR/dema/tests/Dema.Validation.Tests.cs similarity index 100% rename from lib/trends_IIR/dema/Dema.Validation.Tests.cs rename to lib/trends_IIR/dema/tests/Dema.Validation.Tests.cs diff --git a/lib/trends_IIR/dsma/Dsma.md b/lib/trends_IIR/dsma/Dsma.md index 50d8ab12..93771e46 100644 --- a/lib/trends_IIR/dsma/Dsma.md +++ b/lib/trends_IIR/dsma/Dsma.md @@ -158,89 +158,6 @@ DSMA is not implemented in mainstream libraries (TA-Lib, Skender, Tulip, Ooples) - **Bounds**: Output remains within [min, max] price range ±1% tolerance - **Mathematical Consistency**: Streaming updates match batch calculations (ε < 1e-10) -## C# Implementation Considerations - -### State Management - -DSMA uses a comprehensive State record struct combining all filter stages: - -```csharp -[StructLayout(LayoutKind.Auto)] -private record struct State -{ - public double Filt; // current filtered value - public double Filt1; // filt[t-1] - public double Filt2; // filt[t-2] - public double Zeros1; // deviation[t-1] - public double SumSquared; // running sum for RMS - public double Result; // current DSMA value - public double LastPrice; // last valid price - public int Bars; -} -``` - -Bar correction requires coordinated rollback of both state and RingBuffer: - -```csharp -if (isNew) { _p_state = _state; _filtSquaredBuffer.Snapshot(); } -else { _state = _p_state; _filtSquaredBuffer.Restore(); } -``` - -### RingBuffer for RMS - -The RingBuffer maintains O(1) running sum updates for RMS calculation: - -```csharp -double removed = _filtSquaredBuffer.Add(filtSq); -_state.SumSquared = Math.FusedMultiplyAdd(-1.0, removed, _state.SumSquared + filtSq); -``` - -The buffer's `Snapshot()`/`Restore()` methods enable atomic rollback on bar corrections. - -### Precomputed Constants - -Constructor calculates all filter coefficients once: - -```csharp -double arg = SqrtTwo * Math.PI / (period * 0.5); -double a1 = Math.Exp(-arg); -_b1 = 2.0 * a1 * Math.Cos(arg); -_a1Sq = a1 * a1; -_c1Half = (1.0 - _b1 + _a1Sq) * 0.5; -_periodRecip = 1.0 / period; -_scaleAdjustment = scaleFactor * 5.0 / period; -``` - -### FMA Usage - -FMA optimizes the Super Smoother IIR and adaptive EMA: - -```csharp -// Super Smoother: filt = c1Half*(zeros+zeros1) + b1*filt1 - a1Sq*filt2 -double filtPart2 = Math.FusedMultiplyAdd(_state.Filt1, _b1, -_a1Sq * _state.Filt2); - -// Adaptive EMA: result = prevResult*decay + alpha*value -double result = Math.FusedMultiplyAdd(_state.Result, decay, alpha * value); -``` - -### Memory Layout - -| Field | Type | Size | Purpose | -| :--- | :--- | :---: | :--- | -| `_b1` | double | 8B | Super Smoother coefficient | -| `_c1Half` | double | 8B | Halved c₁ coefficient | -| `_a1Sq` | double | 8B | a₁² coefficient | -| `_periodRecip` | double | 8B | 1/period | -| `_scaleAdjustment` | double | 8B | Combined scale factor | -| `_filtSquaredBuffer` | RingBuffer | ~8B+period×8B | Circular buffer for RMS | -| `_state` | State | ~64B | Current calculation state | -| `_p_state` | State | ~64B | Previous state for rollback | -| **Total (fixed)** | | **~176B + period×8B** | Per indicator instance | - -### SIMD Limitations - -The 2-pole IIR recursion and adaptive alpha dependency on running RMS preclude SIMD parallelization across bars. The `Calculate(Span)` method uses a scalar loop—parallelization should target multiple independent series rather than within-series vectorization. - ## Common Pitfalls 1. **Warmup Period**: DSMA requires `Period` bars to fill the Super Smoother delay line and RMS buffer. The first `Period` outputs will be unstable. Use `IsHot` to detect when the indicator has sufficient history. diff --git a/lib/trends_IIR/dsma/Dsma.Quantower.Tests.cs b/lib/trends_IIR/dsma/tests/Dsma.Quantower.Tests.cs similarity index 100% rename from lib/trends_IIR/dsma/Dsma.Quantower.Tests.cs rename to lib/trends_IIR/dsma/tests/Dsma.Quantower.Tests.cs diff --git a/lib/trends_IIR/dsma/Dsma.Tests.cs b/lib/trends_IIR/dsma/tests/Dsma.Tests.cs similarity index 100% rename from lib/trends_IIR/dsma/Dsma.Tests.cs rename to lib/trends_IIR/dsma/tests/Dsma.Tests.cs diff --git a/lib/trends_IIR/dsma/Dsma.Validation.Tests.cs b/lib/trends_IIR/dsma/tests/Dsma.Validation.Tests.cs similarity index 100% rename from lib/trends_IIR/dsma/Dsma.Validation.Tests.cs rename to lib/trends_IIR/dsma/tests/Dsma.Validation.Tests.cs diff --git a/lib/trends_IIR/ema/Ema.Quantower.Tests.cs b/lib/trends_IIR/ema/tests/Ema.Quantower.Tests.cs similarity index 100% rename from lib/trends_IIR/ema/Ema.Quantower.Tests.cs rename to lib/trends_IIR/ema/tests/Ema.Quantower.Tests.cs diff --git a/lib/trends_IIR/ema/Ema.Tests.cs b/lib/trends_IIR/ema/tests/Ema.Tests.cs similarity index 100% rename from lib/trends_IIR/ema/Ema.Tests.cs rename to lib/trends_IIR/ema/tests/Ema.Tests.cs diff --git a/lib/trends_IIR/ema/Ema.Validation.Tests.cs b/lib/trends_IIR/ema/tests/Ema.Validation.Tests.cs similarity index 100% rename from lib/trends_IIR/ema/Ema.Validation.Tests.cs rename to lib/trends_IIR/ema/tests/Ema.Validation.Tests.cs diff --git a/lib/trends_IIR/frama/Frama.md b/lib/trends_IIR/frama/Frama.md index afc311cf..518bb194 100644 --- a/lib/trends_IIR/frama/Frama.md +++ b/lib/trends_IIR/frama/Frama.md @@ -122,103 +122,6 @@ FRAMA is not implemented in the common TA libraries used by QuanTAlib. Validatio | **Ooples** | N/A | Not implemented | | **PineScript** | ✅ | Matches `lib/trends_IIR/frama/frama.pine` | -## C# Implementation Considerations - -### State Management - -FRAMA uses a compact State struct with dual RingBuffer tracking: - -```csharp -[StructLayout(LayoutKind.Sequential)] -private struct State -{ - public double Frama; - public double LastHigh; - public double LastLow; - public int Bars; - public bool HasValue; -} -``` - -Bar correction requires coordinated rollback of state and both ring buffers: - -```csharp -if (isNew) { _p_state = _state; _highs.Snapshot(); _lows.Snapshot(); } -else { _state = _p_state; _highs.Restore(); _lows.Restore(); } -``` - -### Dual RingBuffer Architecture - -FRAMA maintains separate High and Low buffers for fractal dimension calculation: - -```csharp -private readonly RingBuffer _highs; -private readonly RingBuffer _lows; -``` - -The `GetMax` and `GetMin` helper methods scan these buffers for range calculations, supporting both recent-half and full-window lookups via `startOffset` parameter. - -### Precomputed Constants - -Constructor enforces even period and precalculates half-period: - -```csharp -int pe = (period % 2 == 0) ? period : period + 1; -_periodEven = pe; -_half = pe / 2; -``` - -Alpha bounds are compile-time constants: - -```csharp -private const double AlphaFloor = 0.01; -private const double AlphaCeil = 1.0; -private const double Log2 = 0.693147180559945309417232121458176568; -``` - -### FMA Usage - -The final EMA update uses FusedMultiplyAdd: - -```csharp -double result = Math.FusedMultiplyAdd(prev, 1.0 - alpha, alpha * price); -``` - -### TBar Input Support - -FRAMA accepts TBar input for proper High/Low access, with TValue fallback: - -```csharp -public TValue Update(TValue input, bool isNew = true) -{ - return Update(new TBar(input.Time, input.Value, input.Value, - input.Value, input.Value, 0), isNew); -} -``` - -### Memory Layout - -| Field | Type | Size | Purpose | -| :--- | :--- | :---: | :--- | -| `_periodEven` | int | 4B | Even-adjusted period | -| `_half` | int | 4B | Half period for ranges | -| `_highs` | RingBuffer | ~8B+period×8B | High values buffer | -| `_lows` | RingBuffer | ~8B+period×8B | Low values buffer | -| `_state` | State | ~32B | Current calculation state | -| `_p_state` | State | ~32B | Previous state for rollback | -| **Total** | | **~88B + 2×period×8B** | Per indicator instance | - -### Range Scan Implementation - -The `GetMax`/`GetMin` methods perform O(N) linear scans with modular indexing: - -```csharp -int idx = start + offset + i; -if (idx >= capacity) idx -= capacity; -``` - -This approach is simple and cache-friendly for typical periods (10-50). Monotonic deque optimization would reduce to O(1) amortized but adds complexity. - ## Common Pitfalls 1. **Period parity**: The algorithm requires even `N`. Odd values are rounded up. diff --git a/lib/trends_IIR/frama/Frama.Quantower.Tests.cs b/lib/trends_IIR/frama/tests/Frama.Quantower.Tests.cs similarity index 100% rename from lib/trends_IIR/frama/Frama.Quantower.Tests.cs rename to lib/trends_IIR/frama/tests/Frama.Quantower.Tests.cs diff --git a/lib/trends_IIR/frama/Frama.Tests.cs b/lib/trends_IIR/frama/tests/Frama.Tests.cs similarity index 100% rename from lib/trends_IIR/frama/Frama.Tests.cs rename to lib/trends_IIR/frama/tests/Frama.Tests.cs diff --git a/lib/trends_IIR/frama/Frama.Validation.Tests.cs b/lib/trends_IIR/frama/tests/Frama.Validation.Tests.cs similarity index 100% rename from lib/trends_IIR/frama/Frama.Validation.Tests.cs rename to lib/trends_IIR/frama/tests/Frama.Validation.Tests.cs diff --git a/lib/trends_IIR/gdema/Gdema.Quantower.Tests.cs b/lib/trends_IIR/gdema/tests/Gdema.Quantower.Tests.cs similarity index 100% rename from lib/trends_IIR/gdema/Gdema.Quantower.Tests.cs rename to lib/trends_IIR/gdema/tests/Gdema.Quantower.Tests.cs diff --git a/lib/trends_IIR/gdema/Gdema.Tests.cs b/lib/trends_IIR/gdema/tests/Gdema.Tests.cs similarity index 100% rename from lib/trends_IIR/gdema/Gdema.Tests.cs rename to lib/trends_IIR/gdema/tests/Gdema.Tests.cs diff --git a/lib/trends_IIR/gdema/Gdema.Validation.Tests.cs b/lib/trends_IIR/gdema/tests/Gdema.Validation.Tests.cs similarity index 100% rename from lib/trends_IIR/gdema/Gdema.Validation.Tests.cs rename to lib/trends_IIR/gdema/tests/Gdema.Validation.Tests.cs diff --git a/lib/trends_IIR/hema/Hema.md b/lib/trends_IIR/hema/Hema.md index b00679cb..64a4ac05 100644 --- a/lib/trends_IIR/hema/Hema.md +++ b/lib/trends_IIR/hema/Hema.md @@ -21,7 +21,6 @@ ## An EMA-domain analog of HMA with WMA-lag-matched alphas - HEMA is a Hull-style moving average built entirely from **exponential smoothers**. It preserves the classic HMA pipeline (fast minus slow, then smooth) but replaces WMA sub-filters with EMAs whose alphas are tuned to produce **identical lag** to the WMA stages they replace. At period $N$: HEMA($N$) and HMA($N$) have the same theoretical group delay, but HEMA has infinite memory and smoother transient behavior. ## Historical Context @@ -218,91 +217,6 @@ HEMA is not commonly available in mainstream TA libraries. Validation uses a **r - Cross-check via invariant tests: DC gain, step response monotonicity, no NaN propagation after first finite sample. - Streaming vs batch vs span consistency verified in unit tests. -## C# Implementation Considerations - -### State Management - -HEMA uses a comprehensive State struct tracking three EMA stages and warmup: - -```csharp -[StructLayout(LayoutKind.Sequential)] -private struct State -{ - public double EmaSlowRaw; - public double EmaFastRaw; - public double EmaSmoothRaw; - public double DecaySlow; - public double DecayFast; - public double DecaySmooth; - public bool IsHot; - public bool Warmup; -} -``` - -Bar correction uses full state copy plus last-valid tracking: - -```csharp -if (isNew) { _p_state = _state; _p_lastValidValue = _lastValidValue; } -else { _state = _p_state; _lastValidValue = _p_lastValidValue; } -``` - -### Precomputed Constants - -Constructor calculates all alpha/beta pairs and the lag ratio once using integer floor sub-periods: - -```csharp -int halfPeriod = period / 2; // integer floor, same as HMA -int sqrtPeriod = Math.Max((int)Math.Sqrt(period), 1); // integer floor, same as HMA - -_alphaSlow = AlphaFromWmaLag(period); -_alphaFast = AlphaFromWmaLag(Math.Max(halfPeriod, 1)); -_alphaSmooth = AlphaFromWmaLag(Math.Max(sqrtPeriod, 1)); -_betaSlow = 1.0 - _alphaSlow; -_ratio = Math.Clamp(lagFast / lagSlow, 0.0, MaxRatio); -_invOneMinusRatio = 1.0 / Math.Max(1.0 - _ratio, MinDenominator); -``` - -### WMA-Lag-Matched Alpha Calculation - -A single division replaces the old half-life exponential mapping: - -```csharp -private static double AlphaFromWmaLag(int period) -{ - // WMA-lag-matched alpha: EMA lag = (1-a)/a = (P-1)/3 - // Solving: a = 3/(P+2) - return 3.0 / (Math.Max(period, 1) + 2.0); -} -``` - -### FMA Usage - -All EMA updates use FusedMultiplyAdd for precision and performance: - -```csharp -state.EmaSlowRaw = Math.FusedMultiplyAdd(state.EmaSlowRaw, _betaSlow, _alphaSlow * input); -state.EmaFastRaw = Math.FusedMultiplyAdd(state.EmaFastRaw, _betaFast, _alphaFast * input); -double deLag = Math.FusedMultiplyAdd(-_ratio, emaSlow, emaFast) * _invOneMinusRatio; -``` - -### Memory Layout - -| Field | Type | Size | Purpose | -| :--- | :--- | :---: | :--- | -| `_alphaSlow` | double | 8B | Slow EMA alpha | -| `_alphaFast` | double | 8B | Fast EMA alpha | -| `_alphaSmooth` | double | 8B | Smooth stage alpha | -| `_betaSlow` | double | 8B | 1 - alphaSlow | -| `_betaFast` | double | 8B | 1 - alphaFast | -| `_betaSmooth` | double | 8B | 1 - alphaSmooth | -| `_ratio` | double | 8B | Lag ratio for de-lag | -| `_invOneMinusRatio` | double | 8B | Precomputed divisor | -| `_state` | State | ~56B | Current calculation state | -| `_p_state` | State | ~56B | Previous state for rollback | -| `_lastValidValue` | double | 8B | NaN substitution | -| `_p_lastValidValue` | double | 8B | Previous valid value | -| **Total** | | **~192B** | Per indicator instance | - ## Common Pitfalls 1. **Period semantics are now WMA-lag-matched** diff --git a/lib/trends_IIR/hema/Hema.Quantower.Tests.cs b/lib/trends_IIR/hema/tests/Hema.Quantower.Tests.cs similarity index 100% rename from lib/trends_IIR/hema/Hema.Quantower.Tests.cs rename to lib/trends_IIR/hema/tests/Hema.Quantower.Tests.cs diff --git a/lib/trends_IIR/hema/Hema.Tests.cs b/lib/trends_IIR/hema/tests/Hema.Tests.cs similarity index 100% rename from lib/trends_IIR/hema/Hema.Tests.cs rename to lib/trends_IIR/hema/tests/Hema.Tests.cs diff --git a/lib/trends_IIR/hema/Hema.Validation.Tests.cs b/lib/trends_IIR/hema/tests/Hema.Validation.Tests.cs similarity index 100% rename from lib/trends_IIR/hema/Hema.Validation.Tests.cs rename to lib/trends_IIR/hema/tests/Hema.Validation.Tests.cs diff --git a/lib/trends_IIR/holt/Holt.Quantower.Tests.cs b/lib/trends_IIR/holt/tests/Holt.Quantower.Tests.cs similarity index 100% rename from lib/trends_IIR/holt/Holt.Quantower.Tests.cs rename to lib/trends_IIR/holt/tests/Holt.Quantower.Tests.cs diff --git a/lib/trends_IIR/holt/Holt.Tests.cs b/lib/trends_IIR/holt/tests/Holt.Tests.cs similarity index 100% rename from lib/trends_IIR/holt/Holt.Tests.cs rename to lib/trends_IIR/holt/tests/Holt.Tests.cs diff --git a/lib/trends_IIR/holt/Holt.Validation.Tests.cs b/lib/trends_IIR/holt/tests/Holt.Validation.Tests.cs similarity index 100% rename from lib/trends_IIR/holt/Holt.Validation.Tests.cs rename to lib/trends_IIR/holt/tests/Holt.Validation.Tests.cs diff --git a/lib/trends_IIR/htit/Htit.md b/lib/trends_IIR/htit/Htit.md index 403a3b4e..68cd511f 100644 --- a/lib/trends_IIR/htit/Htit.md +++ b/lib/trends_IIR/htit/Htit.md @@ -13,7 +13,6 @@ | **PineScript** | [htit.pine](htit.pine) | | **Signature** | [htit_signature](htit_signature.md) | - - HTIT (Hilbert Transform Instantaneous Trend) is a trend-following indicator that doesn't rely on simple averaging. - No configurable parameters; computation is stateless per bar. - Output range: Tracks input. @@ -179,100 +178,3 @@ The differences with Skender and Ooples arise from: 1. **Initialization**: How the first few bars are handled. 2. **Precision**: Hardcoded decimals vs exact fractions. 3. **Period Constraints**: How strictly the [6, 50] bounds are enforced during intermediate steps. - -## C# Implementation Considerations - -### State Management - -HTIT uses a compact record struct for Hilbert Transform state tracking: - -```csharp -[StructLayout(LayoutKind.Auto)] -private record struct State( - double I2, double Q2, double Re, double Im, - double Period, double SmoothPeriod, - double LastValidPrice, int Index -); -``` - -Bar correction uses simple state copy (no RingBuffer snapshot needed for state struct): - -```csharp -if (isNew) { _p_state = _state; _state.Index++; } -else { _state = _p_state; } -``` - -### Multiple RingBuffers - -HTIT maintains six separate circular buffers for the multi-stage pipeline: - -```csharp -private readonly RingBuffer _priceBuffer; // 64 elements (for IT sum) -private readonly RingBuffer _smoothBuffer; // 8 elements -private readonly RingBuffer _detrenderBuffer; // 8 elements -private readonly RingBuffer _i1Buffer; // 8 elements -private readonly RingBuffer _q1Buffer; // 8 elements -private readonly RingBuffer _itBuffer; // 8 elements -``` - -The price buffer is larger (64) to support IT calculation over up to 50 bars. - -### Precomputed Constants - -High-precision rational constants avoid rounding accumulation: - -```csharp -private const double c1 = 5.0 / 52.0; // ~0.09615385 -private const double c2 = 15.0 / 26.0; // ~0.57692308 -private const double adjSlope = 3.0 / 40.0; // 0.075 -private const double adjIntercept = 27.0 / 50.0; // 0.54 -private const double TwoPi = 2.0 * Math.PI; -``` - -### FMA Usage - -Smoothing operations use FusedMultiplyAdd for precision: - -```csharp -_state.I2 = Math.FusedMultiplyAdd(0.2, i2_val, 0.8 * _p_state.I2); -_state.Q2 = Math.FusedMultiplyAdd(0.2, q2_val, 0.8 * _p_state.Q2); -_state.Re = Math.FusedMultiplyAdd(0.2, re_val, 0.8 * _p_state.Re); -_state.Period = Math.FusedMultiplyAdd(0.2, period, 0.8 * prevPeriod); -``` - -### Stack-Allocated Calculate Method - -The static `Calculate(Span)` method uses stackalloc for zero-allocation batch processing: - -```csharp -Span priceBuffer = stackalloc double[64]; -Span smoothBuffer = stackalloc double[8]; -// ... etc -const int Mask63 = 63; // Power-of-2 masking for circular index -const int Mask7 = 7; -``` - -### Memory Layout - -| Field | Type | Size | Purpose | -| :--- | :--- | :---: | :--- | -| `_priceBuffer` | RingBuffer | ~8B+512B | Price history (64×8B) | -| `_smoothBuffer` | RingBuffer | ~8B+64B | Smoothed prices (8×8B) | -| `_detrenderBuffer` | RingBuffer | ~8B+64B | Detrender output | -| `_i1Buffer` | RingBuffer | ~8B+64B | In-phase component | -| `_q1Buffer` | RingBuffer | ~8B+64B | Quadrature component | -| `_itBuffer` | RingBuffer | ~8B+64B | Instantaneous trend | -| `_state` | State | ~64B | Current Hilbert state | -| `_p_state` | State | ~64B | Previous state for rollback | -| **Total** | | **~960B** | Per indicator instance | - -### Numerical Robustness - -Uses `Math.Atan2` for proper quadrant handling in phase calculation, avoiding division-by-zero issues that plague `atan(y/x)` implementations. - -### Common Pitfalls - -1. **Warmup**: This indicator needs significant warmup (at least 12 bars, ideally 50+) for the feedback loops (period smoothing) to stabilize. Don't trust the first 50 bars. -2. **Lag**: While it adapts, the trendline still lags because it's essentially a dynamic SMA. The advantage is that the period is optimal for the current market condition, not that it has zero lag. -3. **Complexity**: Debugging this is a nightmare. Trust the math. -4. **Ranging Markets**: In a pure range, the "trend" should be flat. HTIT handles this well because the cycle cancellation works best when the cycle is clear. diff --git a/lib/trends_IIR/htit/Htit.Quantower.Tests.cs b/lib/trends_IIR/htit/tests/Htit.Quantower.Tests.cs similarity index 100% rename from lib/trends_IIR/htit/Htit.Quantower.Tests.cs rename to lib/trends_IIR/htit/tests/Htit.Quantower.Tests.cs diff --git a/lib/trends_IIR/htit/Htit.Tests.cs b/lib/trends_IIR/htit/tests/Htit.Tests.cs similarity index 100% rename from lib/trends_IIR/htit/Htit.Tests.cs rename to lib/trends_IIR/htit/tests/Htit.Tests.cs diff --git a/lib/trends_IIR/htit/Htit.Validation.Tests.cs b/lib/trends_IIR/htit/tests/Htit.Validation.Tests.cs similarity index 100% rename from lib/trends_IIR/htit/Htit.Validation.Tests.cs rename to lib/trends_IIR/htit/tests/Htit.Validation.Tests.cs diff --git a/lib/trends_IIR/hwma/Hwma.md b/lib/trends_IIR/hwma/Hwma.md index 1efad223..e20dadf2 100644 --- a/lib/trends_IIR/hwma/Hwma.md +++ b/lib/trends_IIR/hwma/Hwma.md @@ -177,70 +177,6 @@ QuanTAlib validates HWMA against its PineScript reference implementation. | **Tulip** | ❌ | Not included. | | **Ooples** | ❌ | Not included. | -### C# Implementation Considerations - -The QuanTAlib HWMA implementation optimizes triple exponential smoothing through FMA operations and precomputed decay constants: - -**Precomputed Decay Constants** -```csharp -_alpha = 2.0 / (period + 1.0); -_beta = 1.0 / period; -_gamma = 1.0 / period; -_decayAlpha = 1.0 - _alpha; -_decayBeta = 1.0 - _beta; -_decayGamma = 1.0 - _gamma; -``` -All six constants computed once at construction. The decay values (1-α, 1-β, 1-γ) avoid repeated subtraction per tick. - -**State Record Struct with Auto Layout** -```csharp -[StructLayout(LayoutKind.Auto)] -private record struct State( - double F, double V, double A, - double LastValidValue, - bool IsInitialized -); -private State _state; -private State _p_state; -``` -Compiler optimizes field ordering. Three smoothing components plus validation tracking fit in ~41 bytes. - -**FusedMultiplyAdd Throughout** -```csharp -double forecast = prevF + prevV + 0.5 * prevA; -double newF = Math.FusedMultiplyAdd(forecast, _decayAlpha, _alpha * val); -double newV = Math.FusedMultiplyAdd(prevV + prevA, _decayBeta, _beta * (newF - prevF)); -double newA = Math.FusedMultiplyAdd(prevA, _decayGamma, _gamma * (newV - prevV)); -``` -All three component updates use FMA for `a*b+c` patterns, reducing rounding error and leveraging hardware acceleration. - -**O(1) Memory Footprint** -Unlike FIR filters, HWMA requires no buffer—only state variables. No `ArrayPool`, no `stackalloc`, no circular buffer management. - -**Dual Constructor API** -```csharp -public Hwma(int period = 10) // Derives α, β, γ from period -public Hwma(double alpha, double beta, double gamma) // Explicit smoothing factors -``` -Period-based constructor for common use; explicit factors for fine-tuned control with validation. - -**Memory Layout** - -| Field | Type | Size | Notes | -|:------|:-----|-----:|:------| -| `_period` | int | 4B | Conceptual period (display) | -| `_alpha` | double | 8B | Level smoothing | -| `_beta` | double | 8B | Velocity smoothing | -| `_gamma` | double | 8B | Acceleration smoothing | -| `_decayAlpha` | double | 8B | 1 - α | -| `_decayBeta` | double | 8B | 1 - β | -| `_decayGamma` | double | 8B | 1 - γ | -| `_state` | State | ~41B | F, V, A, lastValid, init flag | -| `_p_state` | State | ~41B | Previous state for rollback | -| **Total** | | ~142B | Fixed size, no period scaling | - -HWMA has constant memory regardless of period—approximately **142 bytes** per instance. - ## Common Pitfalls 1. **Overshoot During Reversals**: HWMA's acceleration component can cause overshoot when trends reverse sharply. The filter "expects" the trend to continue and takes time to adapt. Consider lower β/γ values for less aggressive acceleration tracking. diff --git a/lib/trends_IIR/hwma/Hwma.Quantower.Tests.cs b/lib/trends_IIR/hwma/tests/Hwma.Quantower.Tests.cs similarity index 100% rename from lib/trends_IIR/hwma/Hwma.Quantower.Tests.cs rename to lib/trends_IIR/hwma/tests/Hwma.Quantower.Tests.cs diff --git a/lib/trends_IIR/hwma/Hwma.Tests.cs b/lib/trends_IIR/hwma/tests/Hwma.Tests.cs similarity index 100% rename from lib/trends_IIR/hwma/Hwma.Tests.cs rename to lib/trends_IIR/hwma/tests/Hwma.Tests.cs diff --git a/lib/trends_IIR/hwma/Hwma.Validation.Tests.cs b/lib/trends_IIR/hwma/tests/Hwma.Validation.Tests.cs similarity index 100% rename from lib/trends_IIR/hwma/Hwma.Validation.Tests.cs rename to lib/trends_IIR/hwma/tests/Hwma.Validation.Tests.cs diff --git a/lib/trends_IIR/jma/Jma.md b/lib/trends_IIR/jma/Jma.md index 8880e000..24e670f3 100644 --- a/lib/trends_IIR/jma/Jma.md +++ b/lib/trends_IIR/jma/Jma.md @@ -267,109 +267,6 @@ JMA is proprietary. No open-source library implements it. Validation is performe 7. **Using isNew Incorrectly**: When processing live ticks within the same bar, use `Update(value, isNew: false)`. When a new bar opens, use `isNew: true` (default). Getting this wrong corrupts state and buffer snapshots. -## C# Implementation Considerations - -### Dual RingBuffer Architecture - -The implementation uses two `RingBuffer` instances: -- `_devBuffer` (10 samples): Tracks local deviation for short-term volatility SMA -- `_volBuffer` (128 samples): Maintains the volatility distribution for trimmed mean calculation - -Both buffers support `Snapshot()` / `Restore()` for bar correction when `isNew=false`. - -### State Record Struct with Auto Layout - -All IIR filter state is packed into a `record struct` with `LayoutKind.Auto` for compiler-optimized field ordering: - -```csharp -[StructLayout(LayoutKind.Auto)] -private record struct State -{ - public double UpperBand; - public double LowerBand; - public double LastC0; - public double LastC8; - public double LastA8; - public double LastJma; - public double LastPrice; - public int Bars; -} -``` - -### Precomputed Logarithms for Exp Optimization - -Instead of computing `Math.Pow(base, exponent)` on every bar, the implementation precomputes `log(base)` and uses `Math.Exp(log_base * exponent)`: - -```csharp -_logLengthDivider = Math.Log(Math.Max(_lengthDivider, 1e-12)); -_logSqrtDivider = Math.Log(Math.Max(sqrtDivider, 1e-12)); -// Later: Math.Exp(_logLengthDivider * d) instead of Math.Pow(_lengthDivider, d) -``` - -This replaces expensive `Math.Pow` (~80 cycles) with `Math.Exp` (~50 cycles). - -### FusedMultiplyAdd for IIR Calculations - -All EMA and IIR filter operations use `Math.FusedMultiplyAdd` for hardware-optimized precision: - -```csharp -double c0 = Math.FusedMultiplyAdd(_state.LastC0, alpha, decay * value); -double c8 = Math.FusedMultiplyAdd(_state.LastC8, _lengthDivider, lengthDecay * (value - c0)); -double a8 = Math.FusedMultiplyAdd(_state.LastA8, alpha2, Math.FusedMultiplyAdd(_phaseParam, c8, c0 - prevJma) * coef); -``` - -### Stack-Allocated Sorting Buffer - -The trimmed mean calculation uses `stackalloc` instead of heap allocation: - -```csharp -Span sorted = stackalloc double[count]; // max 1KB for 128 doubles -_volBuffer.CopyTo(sorted); -sorted.Sort(); -``` - -This eliminates GC pressure during the per-bar sort operation. - -### SIMD-Accelerated Summation - -The trimmed mean summation uses `SumSIMD()` extension method for vectorized addition of the 65 central values: - -```csharp -return sorted.Slice(start, len).SumSIMD() / len; -``` - -### Bar Correction via State + Buffer Snapshots - -The `_state` / `_p_state` pattern combined with buffer snapshots enables bar correction: - -```csharp -if (isNew) -{ - _p_state = _state; - _devBuffer.Snapshot(); - _volBuffer.Snapshot(); -} -else -{ - _state = _p_state; - _devBuffer.Restore(); - _volBuffer.Restore(); -} -``` - -### Aggressive Inlining - -All hot-path methods are decorated with `[MethodImpl(MethodImplOptions.AggressiveInlining)]`: -- `Step()`, `HandleStateSnapshot()`, `UpdateBands()`, `CalculateIIRFilter()` -- `CalculateJurikExponent()`, `CalculateTrimmedMean()` - -### Memory Layout Summary - -- **Two RingBuffers**: 10 × 8 + 128 × 8 = 1,104 bytes -- **State struct**: ~72 bytes (8 doubles + 1 int) -- **Precomputed coefficients**: ~56 bytes (7 doubles) -- **Total per instance**: ~1,250 bytes typical - ## References - Jurik Research. (1998-2005). "JMA White Papers." *jurikres.com* (archived). diff --git a/lib/trends_IIR/jma/Jma.Quantower.Tests.cs b/lib/trends_IIR/jma/tests/Jma.Quantower.Tests.cs similarity index 100% rename from lib/trends_IIR/jma/Jma.Quantower.Tests.cs rename to lib/trends_IIR/jma/tests/Jma.Quantower.Tests.cs diff --git a/lib/trends_IIR/jma/Jma.Tests.cs b/lib/trends_IIR/jma/tests/Jma.Tests.cs similarity index 100% rename from lib/trends_IIR/jma/Jma.Tests.cs rename to lib/trends_IIR/jma/tests/Jma.Tests.cs diff --git a/lib/trends_IIR/jma/Jma.Validation.Tests.cs b/lib/trends_IIR/jma/tests/Jma.Validation.Tests.cs similarity index 100% rename from lib/trends_IIR/jma/Jma.Validation.Tests.cs rename to lib/trends_IIR/jma/tests/Jma.Validation.Tests.cs diff --git a/lib/trends_IIR/jma/Jma.ZeroDiv.Tests.cs b/lib/trends_IIR/jma/tests/Jma.ZeroDiv.Tests.cs similarity index 100% rename from lib/trends_IIR/jma/Jma.ZeroDiv.Tests.cs rename to lib/trends_IIR/jma/tests/Jma.ZeroDiv.Tests.cs diff --git a/lib/trends_IIR/kama/Kama.md b/lib/trends_IIR/kama/Kama.md index 7c7f123d..2a9dd019 100644 --- a/lib/trends_IIR/kama/Kama.md +++ b/lib/trends_IIR/kama/Kama.md @@ -111,109 +111,3 @@ Validated against TA-Lib, Skender, Tulip, and Ooples. | **Skender** | ✅ | Matches `GetKama` | | **Tulip** | ✅ | Matches `kama` | | **Ooples** | ✅ | Matches `CalculateKaufmanAdaptiveMovingAverage` | - -## C# Implementation Considerations - -### Buffer Strategy - -KAMA uses a **RingBuffer** for the sliding price window: - -```csharp -private readonly RingBuffer _buffer; // period + 1 values -``` - -The buffer stores `period + 1` values to calculate the net change (`Price[0] - Price[period]`) while maintaining incremental volatility updates. Buffer indexing uses `[^1]` for newest, `[0]` for oldest, enabling O(1) change calculation. - -### State Management - -State uses a record struct with `LayoutKind.Auto`: - -```csharp -[StructLayout(LayoutKind.Auto)] -private record struct State(double Kama, double VolatilitySum, double NextDiffOut, double LastValidValue); -``` - -| Field | Size | Purpose | -| :--- | :---: | :--- | -| `Kama` | 8 bytes | Current KAMA value | -| `VolatilitySum` | 8 bytes | Running sum of |ΔP| | -| `NextDiffOut` | 8 bytes | Pre-staged diff for next removal | -| `LastValidValue` | 8 bytes | NaN substitution fallback | -| **Total** | **32 bytes** | Compact state for rollback | - -The `NextDiffOut` field enables O(1) volatility updates by pre-calculating `|buffer[0] - buffer[1]|` — the value that will exit the window on the next bar. - -### FMA Optimization - -Two FMA operations replace traditional arithmetic in the hot path: - -**Smoothing Constant calculation:** - -```csharp -// sc = er * (fastAlpha - slowAlpha) + slowAlpha -double sc = Math.FusedMultiplyAdd(er, _fastAlpha - _slowAlpha, _slowAlpha); -sc *= sc; // SC squaring for noise suppression -``` - -**KAMA update:** - -```csharp -// kama = prevKama + sc * (val - prevKama) -_state.Kama = Math.FusedMultiplyAdd(sc, val - prevKama, prevKama); -``` - -Both follow the EMA smoothing pattern `α·new + (1-α)·old` expressed as FMA. - -### Precomputed Constants - -Alpha values are computed once at construction: - -```csharp -_fastAlpha = 2.0 / (fastPeriod + 1); // Typically 2/3 ≈ 0.667 -_slowAlpha = 2.0 / (slowPeriod + 1); // Typically 2/31 ≈ 0.065 -``` - -The difference `_fastAlpha - _slowAlpha` is computed at runtime (not stored) since it's used only once per bar. - -### Static Calculate Path - -The span-based method uses conditional allocation: - -```csharp -Span buffer = bufSize <= 256 ? stackalloc double[bufSize] : new double[bufSize]; -``` - -For typical periods (≤255), this allocates on the stack. The circular buffer logic uses modular arithmetic: - -```csharp -int prevIdx = (bufferIdx - 1 + bufSize) % bufSize; -int oldestIdx = (bufferIdx + 1) % bufSize; -bufferIdx = (bufferIdx + 1) % bufSize; -``` - -### Efficiency Ratio Bounds - -The implementation guards against edge cases: - -```csharp -double er = (volatility > 1e-10) ? change / volatility : 0.0; -if (er > 1.0) er = 1.0; // Cap floating-point drift -``` - -The epsilon guard (1e-10) prevents division by zero in flat markets, while the ER cap handles numerical precision issues where accumulated volatility might slightly undercount actual change. - -### Memory Layout Summary - -| Component | Size | Notes | -| :--- | :---: | :--- | -| RingBuffer | 8 + period×8 bytes | Header + price array | -| State | 32 bytes | 4 doubles | -| p_state | 32 bytes | Rollback copy | -| Constants | 16 bytes | Fast/slow alpha | -| **Per-instance** | **~168 bytes** | For period=10 | - -### Common Pitfalls - -1. **Flatlining**: In very choppy markets, KAMA can become almost horizontal. This is a feature, not a bug—it's telling you to stay out. -2. **Parameters**: The standard settings are (10, 2, 30). 10 is the ER period, 2 is the fast EMA, 30 is the slow EMA. Tweaking the ER period changes the sensitivity to noise. -3. **Trend Following**: KAMA is excellent for trailing stops because it flattens out when momentum stalls. diff --git a/lib/trends_IIR/kama/Kama.Quantower.Tests.cs b/lib/trends_IIR/kama/tests/Kama.Quantower.Tests.cs similarity index 100% rename from lib/trends_IIR/kama/Kama.Quantower.Tests.cs rename to lib/trends_IIR/kama/tests/Kama.Quantower.Tests.cs diff --git a/lib/trends_IIR/kama/Kama.Tests.cs b/lib/trends_IIR/kama/tests/Kama.Tests.cs similarity index 100% rename from lib/trends_IIR/kama/Kama.Tests.cs rename to lib/trends_IIR/kama/tests/Kama.Tests.cs diff --git a/lib/trends_IIR/kama/Kama.Validation.Tests.cs b/lib/trends_IIR/kama/tests/Kama.Validation.Tests.cs similarity index 100% rename from lib/trends_IIR/kama/Kama.Validation.Tests.cs rename to lib/trends_IIR/kama/tests/Kama.Validation.Tests.cs diff --git a/lib/trends_IIR/lema/Lema.Quantower.Tests.cs b/lib/trends_IIR/lema/tests/Lema.Quantower.Tests.cs similarity index 100% rename from lib/trends_IIR/lema/Lema.Quantower.Tests.cs rename to lib/trends_IIR/lema/tests/Lema.Quantower.Tests.cs diff --git a/lib/trends_IIR/lema/Lema.Tests.cs b/lib/trends_IIR/lema/tests/Lema.Tests.cs similarity index 100% rename from lib/trends_IIR/lema/Lema.Tests.cs rename to lib/trends_IIR/lema/tests/Lema.Tests.cs diff --git a/lib/trends_IIR/lema/Lema.Validation.Tests.cs b/lib/trends_IIR/lema/tests/Lema.Validation.Tests.cs similarity index 100% rename from lib/trends_IIR/lema/Lema.Validation.Tests.cs rename to lib/trends_IIR/lema/tests/Lema.Validation.Tests.cs diff --git a/lib/trends_IIR/ltma/Ltma.Quantower.Tests.cs b/lib/trends_IIR/ltma/tests/Ltma.Quantower.Tests.cs similarity index 100% rename from lib/trends_IIR/ltma/Ltma.Quantower.Tests.cs rename to lib/trends_IIR/ltma/tests/Ltma.Quantower.Tests.cs diff --git a/lib/trends_IIR/ltma/Ltma.Tests.cs b/lib/trends_IIR/ltma/tests/Ltma.Tests.cs similarity index 100% rename from lib/trends_IIR/ltma/Ltma.Tests.cs rename to lib/trends_IIR/ltma/tests/Ltma.Tests.cs diff --git a/lib/trends_IIR/ltma/Ltma.Validation.Tests.cs b/lib/trends_IIR/ltma/tests/Ltma.Validation.Tests.cs similarity index 100% rename from lib/trends_IIR/ltma/Ltma.Validation.Tests.cs rename to lib/trends_IIR/ltma/tests/Ltma.Validation.Tests.cs diff --git a/lib/trends_IIR/mama/Mama.Quantower.Tests.cs b/lib/trends_IIR/mama/tests/Mama.Quantower.Tests.cs similarity index 100% rename from lib/trends_IIR/mama/Mama.Quantower.Tests.cs rename to lib/trends_IIR/mama/tests/Mama.Quantower.Tests.cs diff --git a/lib/trends_IIR/mama/Mama.Tests.cs b/lib/trends_IIR/mama/tests/Mama.Tests.cs similarity index 100% rename from lib/trends_IIR/mama/Mama.Tests.cs rename to lib/trends_IIR/mama/tests/Mama.Tests.cs diff --git a/lib/trends_IIR/mama/Mama.Validation.Tests.cs b/lib/trends_IIR/mama/tests/Mama.Validation.Tests.cs similarity index 100% rename from lib/trends_IIR/mama/Mama.Validation.Tests.cs rename to lib/trends_IIR/mama/tests/Mama.Validation.Tests.cs diff --git a/lib/trends_IIR/mavp/Mavp.Quantower.Tests.cs b/lib/trends_IIR/mavp/tests/Mavp.Quantower.Tests.cs similarity index 100% rename from lib/trends_IIR/mavp/Mavp.Quantower.Tests.cs rename to lib/trends_IIR/mavp/tests/Mavp.Quantower.Tests.cs diff --git a/lib/trends_IIR/mavp/Mavp.Tests.cs b/lib/trends_IIR/mavp/tests/Mavp.Tests.cs similarity index 100% rename from lib/trends_IIR/mavp/Mavp.Tests.cs rename to lib/trends_IIR/mavp/tests/Mavp.Tests.cs diff --git a/lib/trends_IIR/mavp/Mavp.Validation.Tests.cs b/lib/trends_IIR/mavp/tests/Mavp.Validation.Tests.cs similarity index 100% rename from lib/trends_IIR/mavp/Mavp.Validation.Tests.cs rename to lib/trends_IIR/mavp/tests/Mavp.Validation.Tests.cs diff --git a/lib/trends_IIR/mcnma/Mcnma.Quantower.Tests.cs b/lib/trends_IIR/mcnma/tests/Mcnma.Quantower.Tests.cs similarity index 100% rename from lib/trends_IIR/mcnma/Mcnma.Quantower.Tests.cs rename to lib/trends_IIR/mcnma/tests/Mcnma.Quantower.Tests.cs diff --git a/lib/trends_IIR/mcnma/Mcnma.Tests.cs b/lib/trends_IIR/mcnma/tests/Mcnma.Tests.cs similarity index 100% rename from lib/trends_IIR/mcnma/Mcnma.Tests.cs rename to lib/trends_IIR/mcnma/tests/Mcnma.Tests.cs diff --git a/lib/trends_IIR/mcnma/Mcnma.Validation.Tests.cs b/lib/trends_IIR/mcnma/tests/Mcnma.Validation.Tests.cs similarity index 100% rename from lib/trends_IIR/mcnma/Mcnma.Validation.Tests.cs rename to lib/trends_IIR/mcnma/tests/Mcnma.Validation.Tests.cs diff --git a/lib/trends_IIR/mgdi/Mgdi.Quantower.Tests.cs b/lib/trends_IIR/mgdi/tests/Mgdi.Quantower.Tests.cs similarity index 100% rename from lib/trends_IIR/mgdi/Mgdi.Quantower.Tests.cs rename to lib/trends_IIR/mgdi/tests/Mgdi.Quantower.Tests.cs diff --git a/lib/trends_IIR/mgdi/Mgdi.Tests.cs b/lib/trends_IIR/mgdi/tests/Mgdi.Tests.cs similarity index 100% rename from lib/trends_IIR/mgdi/Mgdi.Tests.cs rename to lib/trends_IIR/mgdi/tests/Mgdi.Tests.cs diff --git a/lib/trends_IIR/mgdi/Mgdi.Validation.Tests.cs b/lib/trends_IIR/mgdi/tests/Mgdi.Validation.Tests.cs similarity index 100% rename from lib/trends_IIR/mgdi/Mgdi.Validation.Tests.cs rename to lib/trends_IIR/mgdi/tests/Mgdi.Validation.Tests.cs diff --git a/lib/trends_IIR/mma/Mma.Quantower.Tests.cs b/lib/trends_IIR/mma/tests/Mma.Quantower.Tests.cs similarity index 100% rename from lib/trends_IIR/mma/Mma.Quantower.Tests.cs rename to lib/trends_IIR/mma/tests/Mma.Quantower.Tests.cs diff --git a/lib/trends_IIR/mma/Mma.Tests.cs b/lib/trends_IIR/mma/tests/Mma.Tests.cs similarity index 100% rename from lib/trends_IIR/mma/Mma.Tests.cs rename to lib/trends_IIR/mma/tests/Mma.Tests.cs diff --git a/lib/trends_IIR/mma/Mma.Validation.Tests.cs b/lib/trends_IIR/mma/tests/Mma.Validation.Tests.cs similarity index 100% rename from lib/trends_IIR/mma/Mma.Validation.Tests.cs rename to lib/trends_IIR/mma/tests/Mma.Validation.Tests.cs diff --git a/lib/trends_IIR/nma/Nma.Quantower.Tests.cs b/lib/trends_IIR/nma/tests/Nma.Quantower.Tests.cs similarity index 100% rename from lib/trends_IIR/nma/Nma.Quantower.Tests.cs rename to lib/trends_IIR/nma/tests/Nma.Quantower.Tests.cs diff --git a/lib/trends_IIR/nma/Nma.Tests.cs b/lib/trends_IIR/nma/tests/Nma.Tests.cs similarity index 100% rename from lib/trends_IIR/nma/Nma.Tests.cs rename to lib/trends_IIR/nma/tests/Nma.Tests.cs diff --git a/lib/trends_IIR/nma/Nma.Validation.Tests.cs b/lib/trends_IIR/nma/tests/Nma.Validation.Tests.cs similarity index 100% rename from lib/trends_IIR/nma/Nma.Validation.Tests.cs rename to lib/trends_IIR/nma/tests/Nma.Validation.Tests.cs diff --git a/lib/trends_IIR/qema/Qema.Quantower.Tests.cs b/lib/trends_IIR/qema/tests/Qema.Quantower.Tests.cs similarity index 100% rename from lib/trends_IIR/qema/Qema.Quantower.Tests.cs rename to lib/trends_IIR/qema/tests/Qema.Quantower.Tests.cs diff --git a/lib/trends_IIR/qema/Qema.Tests.cs b/lib/trends_IIR/qema/tests/Qema.Tests.cs similarity index 100% rename from lib/trends_IIR/qema/Qema.Tests.cs rename to lib/trends_IIR/qema/tests/Qema.Tests.cs diff --git a/lib/trends_IIR/qema/Qema.Validation.Tests.cs b/lib/trends_IIR/qema/tests/Qema.Validation.Tests.cs similarity index 100% rename from lib/trends_IIR/qema/Qema.Validation.Tests.cs rename to lib/trends_IIR/qema/tests/Qema.Validation.Tests.cs diff --git a/lib/trends_IIR/rema/Rema.Quantower.Tests.cs b/lib/trends_IIR/rema/tests/Rema.Quantower.Tests.cs similarity index 100% rename from lib/trends_IIR/rema/Rema.Quantower.Tests.cs rename to lib/trends_IIR/rema/tests/Rema.Quantower.Tests.cs diff --git a/lib/trends_IIR/rema/Rema.Tests.cs b/lib/trends_IIR/rema/tests/Rema.Tests.cs similarity index 100% rename from lib/trends_IIR/rema/Rema.Tests.cs rename to lib/trends_IIR/rema/tests/Rema.Tests.cs diff --git a/lib/trends_IIR/rema/Rema.Validation.Tests.cs b/lib/trends_IIR/rema/tests/Rema.Validation.Tests.cs similarity index 100% rename from lib/trends_IIR/rema/Rema.Validation.Tests.cs rename to lib/trends_IIR/rema/tests/Rema.Validation.Tests.cs diff --git a/lib/trends_IIR/rgma/Rgma.Quantower.Tests.cs b/lib/trends_IIR/rgma/tests/Rgma.Quantower.Tests.cs similarity index 100% rename from lib/trends_IIR/rgma/Rgma.Quantower.Tests.cs rename to lib/trends_IIR/rgma/tests/Rgma.Quantower.Tests.cs diff --git a/lib/trends_IIR/rgma/Rgma.Tests.cs b/lib/trends_IIR/rgma/tests/Rgma.Tests.cs similarity index 100% rename from lib/trends_IIR/rgma/Rgma.Tests.cs rename to lib/trends_IIR/rgma/tests/Rgma.Tests.cs diff --git a/lib/trends_IIR/rgma/Rgma.Validation.Tests.cs b/lib/trends_IIR/rgma/tests/Rgma.Validation.Tests.cs similarity index 100% rename from lib/trends_IIR/rgma/Rgma.Validation.Tests.cs rename to lib/trends_IIR/rgma/tests/Rgma.Validation.Tests.cs diff --git a/lib/trends_IIR/rma/Rma.Quantower.Tests.cs b/lib/trends_IIR/rma/tests/Rma.Quantower.Tests.cs similarity index 100% rename from lib/trends_IIR/rma/Rma.Quantower.Tests.cs rename to lib/trends_IIR/rma/tests/Rma.Quantower.Tests.cs diff --git a/lib/trends_IIR/rma/Rma.Tests.cs b/lib/trends_IIR/rma/tests/Rma.Tests.cs similarity index 100% rename from lib/trends_IIR/rma/Rma.Tests.cs rename to lib/trends_IIR/rma/tests/Rma.Tests.cs diff --git a/lib/trends_IIR/rma/Rma.Validation.Tests.cs b/lib/trends_IIR/rma/tests/Rma.Validation.Tests.cs similarity index 100% rename from lib/trends_IIR/rma/Rma.Validation.Tests.cs rename to lib/trends_IIR/rma/tests/Rma.Validation.Tests.cs diff --git a/lib/trends_IIR/t3/T3.Quantower.Tests.cs b/lib/trends_IIR/t3/tests/T3.Quantower.Tests.cs similarity index 100% rename from lib/trends_IIR/t3/T3.Quantower.Tests.cs rename to lib/trends_IIR/t3/tests/T3.Quantower.Tests.cs diff --git a/lib/trends_IIR/t3/T3.Tests.cs b/lib/trends_IIR/t3/tests/T3.Tests.cs similarity index 100% rename from lib/trends_IIR/t3/T3.Tests.cs rename to lib/trends_IIR/t3/tests/T3.Tests.cs diff --git a/lib/trends_IIR/t3/T3.Validation.Tests.cs b/lib/trends_IIR/t3/tests/T3.Validation.Tests.cs similarity index 100% rename from lib/trends_IIR/t3/T3.Validation.Tests.cs rename to lib/trends_IIR/t3/tests/T3.Validation.Tests.cs diff --git a/lib/trends_IIR/tema/Tema.md b/lib/trends_IIR/tema/Tema.md index 536b28ba..afc2ca80 100644 --- a/lib/trends_IIR/tema/Tema.md +++ b/lib/trends_IIR/tema/Tema.md @@ -146,89 +146,6 @@ TEMA is inherently recursive due to cascaded EMAs. SIMD parallelization across b | **Tulip** | ✅ | Matches `tema` exactly. | | **Ooples** | ❌ | Diverges significantly due to initialization logic. | -## C# Implementation Considerations - -### State Management - -TEMA maintains six EmaState instances—three current, three previous—enabling atomic rollback on bar corrections: - -```csharp -private record struct EmaState(double Ema, double E, bool IsHot, bool IsCompensated); - -private EmaState _state1, _state2, _state3; -private EmaState _p_state1, _p_state2, _p_state3; -``` - -The `E` field tracks bias compensation factor for each EMA stage independently. Each state auto-transitions via `IsCompensated` flag when bias becomes negligible. - -### Precomputed Constants - -Constructor calculates smoothing constants once: - -```csharp -_alpha = 2.0 / (period + 1); -_decay = 1 - _alpha; -``` - -These constants are reused across all three EMA stages, avoiding repeated division. - -### FMA Usage - -Each EMA update uses FusedMultiplyAdd for the standard EMA formula: - -```csharp -double newEma = Math.FusedMultiplyAdd(state.Ema, _decay, _alpha * input); -``` - -The final TEMA combination `3*e1 - 3*e2 + e3` could use FMA but the coefficients (3, -3, 1) make chained FMA marginal; current implementation uses direct arithmetic. - -### Bar Correction Pattern - -TEMA's cascaded structure requires coordinated state rollback: - -```csharp -if (isNew) -{ - _p_state1 = _state1; - _p_state2 = _state2; - _p_state3 = _state3; -} -else -{ - _state1 = _p_state1; - _state2 = _p_state2; - _state3 = _p_state3; -} -``` - -All three stages rollback atomically, ensuring consistent cascade state when `isNew=false`. - -### Memory Layout - -| Field | Type | Size | Purpose | -| :--- | :--- | :---: | :--- | -| `_alpha` | double | 8B | Smoothing constant | -| `_decay` | double | 8B | 1 - alpha | -| `_state1` | EmaState | 24B | First EMA state | -| `_state2` | EmaState | 24B | Second EMA state | -| `_state3` | EmaState | 24B | Third EMA state | -| `_p_state1` | EmaState | 24B | Previous state 1 | -| `_p_state2` | EmaState | 24B | Previous state 2 | -| `_p_state3` | EmaState | 24B | Previous state 3 | -| **Total** | | **160B** | Per indicator instance | - -Each EmaState contains: Ema (8B), E (8B), IsHot (1B), IsCompensated (1B) + padding (~6B) = ~24B. - -### Common Pitfalls - -1. **Overshoot**: TEMA is so responsive it can overshoot price turns, creating a "whiplash" effect in volatile markets. -2. **Noise**: By reducing lag, TEMA sacrifices some noise suppression. It is "nervous" compared to an SMA. -3. **Identity Crisis**: Often confused with T3 (Tillson). T3 is a generalized version; TEMA is specifically T3 with $v=1$. -4. **Warmup period**: Requires 3× period bars before producing valid output; premature signals are unreliable. -5. **Parameter sensitivity**: Small period values (< 10) create excessive noise; large values (> 50) reduce responsiveness. -6. **False signals**: In choppy, sideways markets, frequent crossovers generate misleading signals. -7. **Computational cost**: 4× more expensive than simple EMA due to cascaded calculations. - ## FAQ **Q: How does TEMA differ from a triple-smoothed EMA?** diff --git a/lib/trends_IIR/tema/Tema.Quantower.Tests.cs b/lib/trends_IIR/tema/tests/Tema.Quantower.Tests.cs similarity index 100% rename from lib/trends_IIR/tema/Tema.Quantower.Tests.cs rename to lib/trends_IIR/tema/tests/Tema.Quantower.Tests.cs diff --git a/lib/trends_IIR/tema/Tema.Tests.cs b/lib/trends_IIR/tema/tests/Tema.Tests.cs similarity index 100% rename from lib/trends_IIR/tema/Tema.Tests.cs rename to lib/trends_IIR/tema/tests/Tema.Tests.cs diff --git a/lib/trends_IIR/tema/Tema.Validation.Tests.cs b/lib/trends_IIR/tema/tests/Tema.Validation.Tests.cs similarity index 100% rename from lib/trends_IIR/tema/Tema.Validation.Tests.cs rename to lib/trends_IIR/tema/tests/Tema.Validation.Tests.cs diff --git a/lib/trends_IIR/trama/Trama.Quantower.Tests.cs b/lib/trends_IIR/trama/tests/Trama.Quantower.Tests.cs similarity index 100% rename from lib/trends_IIR/trama/Trama.Quantower.Tests.cs rename to lib/trends_IIR/trama/tests/Trama.Quantower.Tests.cs diff --git a/lib/trends_IIR/trama/Trama.Tests.cs b/lib/trends_IIR/trama/tests/Trama.Tests.cs similarity index 100% rename from lib/trends_IIR/trama/Trama.Tests.cs rename to lib/trends_IIR/trama/tests/Trama.Tests.cs diff --git a/lib/trends_IIR/trama/Trama.Validation.Tests.cs b/lib/trends_IIR/trama/tests/Trama.Validation.Tests.cs similarity index 100% rename from lib/trends_IIR/trama/Trama.Validation.Tests.cs rename to lib/trends_IIR/trama/tests/Trama.Validation.Tests.cs diff --git a/lib/trends_IIR/vama/Vama.Quantower.Tests.cs b/lib/trends_IIR/vama/tests/Vama.Quantower.Tests.cs similarity index 100% rename from lib/trends_IIR/vama/Vama.Quantower.Tests.cs rename to lib/trends_IIR/vama/tests/Vama.Quantower.Tests.cs diff --git a/lib/trends_IIR/vama/Vama.Tests.cs b/lib/trends_IIR/vama/tests/Vama.Tests.cs similarity index 100% rename from lib/trends_IIR/vama/Vama.Tests.cs rename to lib/trends_IIR/vama/tests/Vama.Tests.cs diff --git a/lib/trends_IIR/vama/Vama.Validation.Tests.cs b/lib/trends_IIR/vama/tests/Vama.Validation.Tests.cs similarity index 100% rename from lib/trends_IIR/vama/Vama.Validation.Tests.cs rename to lib/trends_IIR/vama/tests/Vama.Validation.Tests.cs diff --git a/lib/trends_IIR/vidya/Vidya.Quantower.Tests.cs b/lib/trends_IIR/vidya/tests/Vidya.Quantower.Tests.cs similarity index 100% rename from lib/trends_IIR/vidya/Vidya.Quantower.Tests.cs rename to lib/trends_IIR/vidya/tests/Vidya.Quantower.Tests.cs diff --git a/lib/trends_IIR/vidya/Vidya.Tests.cs b/lib/trends_IIR/vidya/tests/Vidya.Tests.cs similarity index 100% rename from lib/trends_IIR/vidya/Vidya.Tests.cs rename to lib/trends_IIR/vidya/tests/Vidya.Tests.cs diff --git a/lib/trends_IIR/vidya/Vidya.Validation.Tests.cs b/lib/trends_IIR/vidya/tests/Vidya.Validation.Tests.cs similarity index 100% rename from lib/trends_IIR/vidya/Vidya.Validation.Tests.cs rename to lib/trends_IIR/vidya/tests/Vidya.Validation.Tests.cs diff --git a/lib/trends_IIR/yzvama/Yzvama.Quantower.Tests.cs b/lib/trends_IIR/yzvama/tests/Yzvama.Quantower.Tests.cs similarity index 100% rename from lib/trends_IIR/yzvama/Yzvama.Quantower.Tests.cs rename to lib/trends_IIR/yzvama/tests/Yzvama.Quantower.Tests.cs diff --git a/lib/trends_IIR/yzvama/Yzvama.Tests.cs b/lib/trends_IIR/yzvama/tests/Yzvama.Tests.cs similarity index 100% rename from lib/trends_IIR/yzvama/Yzvama.Tests.cs rename to lib/trends_IIR/yzvama/tests/Yzvama.Tests.cs diff --git a/lib/trends_IIR/yzvama/Yzvama.Validation.Tests.cs b/lib/trends_IIR/yzvama/tests/Yzvama.Validation.Tests.cs similarity index 100% rename from lib/trends_IIR/yzvama/Yzvama.Validation.Tests.cs rename to lib/trends_IIR/yzvama/tests/Yzvama.Validation.Tests.cs diff --git a/lib/trends_IIR/zldema/Zldema.Quantower.Tests.cs b/lib/trends_IIR/zldema/tests/Zldema.Quantower.Tests.cs similarity index 100% rename from lib/trends_IIR/zldema/Zldema.Quantower.Tests.cs rename to lib/trends_IIR/zldema/tests/Zldema.Quantower.Tests.cs diff --git a/lib/trends_IIR/zldema/Zldema.Tests.cs b/lib/trends_IIR/zldema/tests/Zldema.Tests.cs similarity index 100% rename from lib/trends_IIR/zldema/Zldema.Tests.cs rename to lib/trends_IIR/zldema/tests/Zldema.Tests.cs diff --git a/lib/trends_IIR/zldema/Zldema.Validation.Tests.cs b/lib/trends_IIR/zldema/tests/Zldema.Validation.Tests.cs similarity index 100% rename from lib/trends_IIR/zldema/Zldema.Validation.Tests.cs rename to lib/trends_IIR/zldema/tests/Zldema.Validation.Tests.cs diff --git a/lib/trends_IIR/zlema/Zlema.Quantower.Tests.cs b/lib/trends_IIR/zlema/tests/Zlema.Quantower.Tests.cs similarity index 100% rename from lib/trends_IIR/zlema/Zlema.Quantower.Tests.cs rename to lib/trends_IIR/zlema/tests/Zlema.Quantower.Tests.cs diff --git a/lib/trends_IIR/zlema/Zlema.Tests.cs b/lib/trends_IIR/zlema/tests/Zlema.Tests.cs similarity index 100% rename from lib/trends_IIR/zlema/Zlema.Tests.cs rename to lib/trends_IIR/zlema/tests/Zlema.Tests.cs diff --git a/lib/trends_IIR/zlema/Zlema.Validation.Tests.cs b/lib/trends_IIR/zlema/tests/Zlema.Validation.Tests.cs similarity index 100% rename from lib/trends_IIR/zlema/Zlema.Validation.Tests.cs rename to lib/trends_IIR/zlema/tests/Zlema.Validation.Tests.cs diff --git a/lib/trends_IIR/zltema/Zltema.Quantower.Tests.cs b/lib/trends_IIR/zltema/tests/Zltema.Quantower.Tests.cs similarity index 100% rename from lib/trends_IIR/zltema/Zltema.Quantower.Tests.cs rename to lib/trends_IIR/zltema/tests/Zltema.Quantower.Tests.cs diff --git a/lib/trends_IIR/zltema/Zltema.Tests.cs b/lib/trends_IIR/zltema/tests/Zltema.Tests.cs similarity index 100% rename from lib/trends_IIR/zltema/Zltema.Tests.cs rename to lib/trends_IIR/zltema/tests/Zltema.Tests.cs diff --git a/lib/trends_IIR/zltema/Zltema.Validation.Tests.cs b/lib/trends_IIR/zltema/tests/Zltema.Validation.Tests.cs similarity index 100% rename from lib/trends_IIR/zltema/Zltema.Validation.Tests.cs rename to lib/trends_IIR/zltema/tests/Zltema.Validation.Tests.cs diff --git a/lib/volatility/adr/Adr.Quantower.Tests.cs b/lib/volatility/adr/tests/Adr.Quantower.Tests.cs similarity index 100% rename from lib/volatility/adr/Adr.Quantower.Tests.cs rename to lib/volatility/adr/tests/Adr.Quantower.Tests.cs diff --git a/lib/volatility/adr/Adr.Tests.cs b/lib/volatility/adr/tests/Adr.Tests.cs similarity index 100% rename from lib/volatility/adr/Adr.Tests.cs rename to lib/volatility/adr/tests/Adr.Tests.cs diff --git a/lib/volatility/adr/Adr.Validation.Tests.cs b/lib/volatility/adr/tests/Adr.Validation.Tests.cs similarity index 100% rename from lib/volatility/adr/Adr.Validation.Tests.cs rename to lib/volatility/adr/tests/Adr.Validation.Tests.cs diff --git a/lib/volatility/atr/Atr.md b/lib/volatility/atr/Atr.md index 7537849f..0836c4fd 100644 --- a/lib/volatility/atr/Atr.md +++ b/lib/volatility/atr/Atr.md @@ -215,79 +215,6 @@ var atr14 = new Atr(source, 14); // ATR updates automatically when bars are added to source ``` -## C# Implementation Considerations - -### Delegation to RMA - -ATR delegates smoothing to an internal RMA instance: - -```csharp -private readonly Rma _rma; -``` - -This reuses RMA's warmup compensation and state management logic. - -### State Management - -```csharp -private TBar _prevBar; // Previous bar for TR calculation -private bool _isInitialized; // First bar flag -``` - -The implementation tracks the previous bar to compute True Range gaps. The `_isInitialized` flag handles the first-bar edge case where no previous close exists. - -### True Range Calculation - -```csharp -[MethodImpl(MethodImplOptions.AggressiveInlining)] -public TValue Update(TBar input, bool isNew = true) -{ - double tr; - if (!_isInitialized) - { - tr = input.High - input.Low; // First bar: H-L only - } - else - { - double hl = input.High - input.Low; - double hpc = Math.Abs(input.High - _prevBar.Close); - double lpc = Math.Abs(input.Low - _prevBar.Close); - tr = Math.Max(hl, Math.Max(hpc, lpc)); - } - // ... RMA smoothing ... -} -``` - -### Batch True Range Calculation - -For TBarSeries input, TR is calculated for all bars first, then passed to RMA: - -```csharp -private static TSeries CalculateTrueRange(TBarSeries source) -{ - // First bar: H - L - v.Add(source[0].High - source[0].Low); - - // Subsequent bars: max of three components - for (int i = 1; i < source.Count; i++) - { - double hl = bar.High - bar.Low; - double hpc = Math.Abs(bar.High - prevBar.Close); - double lpc = Math.Abs(bar.Low - prevBar.Close); - v.Add(Math.Max(hl, Math.Max(hpc, lpc))); - } -} -``` - -### Memory Layout - -| Component | Size | Purpose | -| :-------- | ---: | :------ | -| `_rma` (Rma) | ~40 bytes | RMA smoothing state | -| `_prevBar` (TBar) | 48 bytes | Previous bar for gap calculation | -| `_isInitialized` | 1 byte | First bar flag | -| **Total per instance** | **~90 bytes** | No period-dependent allocations | - ## References - Wilder, J. W. (1978). *New Concepts in Technical Trading Systems*. Trend Research. Chapter: Average True Range. diff --git a/lib/volatility/atr/Atr.Quantower.Tests.cs b/lib/volatility/atr/tests/Atr.Quantower.Tests.cs similarity index 100% rename from lib/volatility/atr/Atr.Quantower.Tests.cs rename to lib/volatility/atr/tests/Atr.Quantower.Tests.cs diff --git a/lib/volatility/atr/Atr.Tests.cs b/lib/volatility/atr/tests/Atr.Tests.cs similarity index 100% rename from lib/volatility/atr/Atr.Tests.cs rename to lib/volatility/atr/tests/Atr.Tests.cs diff --git a/lib/volatility/atr/Atr.Validation.Tests.cs b/lib/volatility/atr/tests/Atr.Validation.Tests.cs similarity index 100% rename from lib/volatility/atr/Atr.Validation.Tests.cs rename to lib/volatility/atr/tests/Atr.Validation.Tests.cs diff --git a/lib/volatility/atrn/Atrn.Quantower.Tests.cs b/lib/volatility/atrn/tests/Atrn.Quantower.Tests.cs similarity index 100% rename from lib/volatility/atrn/Atrn.Quantower.Tests.cs rename to lib/volatility/atrn/tests/Atrn.Quantower.Tests.cs diff --git a/lib/volatility/atrn/Atrn.Tests.cs b/lib/volatility/atrn/tests/Atrn.Tests.cs similarity index 100% rename from lib/volatility/atrn/Atrn.Tests.cs rename to lib/volatility/atrn/tests/Atrn.Tests.cs diff --git a/lib/volatility/atrn/Atrn.Validation.Tests.cs b/lib/volatility/atrn/tests/Atrn.Validation.Tests.cs similarity index 100% rename from lib/volatility/atrn/Atrn.Validation.Tests.cs rename to lib/volatility/atrn/tests/Atrn.Validation.Tests.cs diff --git a/lib/volatility/bbw/Bbw.md b/lib/volatility/bbw/Bbw.md index b931bdaa..073b9e3b 100644 --- a/lib/volatility/bbw/Bbw.md +++ b/lib/volatility/bbw/Bbw.md @@ -219,50 +219,6 @@ var bbw = new Bbw(source, period: 20, multiplier: 2.0); // BBW updates automatically when prices are added to source ``` -## C# Implementation Considerations - -### Delegation to SMA and StdDev - -BBW composes two internal indicators: - -```csharp -private readonly Sma _sma; -private readonly Stddev _stddev; -private readonly double _mult; -``` - -This reuses existing SMA and StdDev implementations with their warmup and state management. - -### Core Calculation - -```csharp -[MethodImpl(MethodImplOptions.AggressiveInlining)] -public TValue Update(TValue input, bool isNew = true) -{ - _sma.Update(input, isNew); - _stddev.Update(input, isNew); - - double smaValue = _sma.Last.Value; - double stdValue = _stddev.Last.Value; - - // Guard against division by zero - double bbw = smaValue > 0 ? (2.0 * _mult * stdValue) / smaValue : 0.0; - - return new TValue(input.Time, bbw); -} -``` - -### Memory Layout - -| Component | Size | Purpose | -| :-------- | ---: | :------ | -| `_sma` (Sma) | ~48 + N×8 bytes | SMA with circular buffer | -| `_stddev` (Stddev) | ~48 + N×8 bytes | StdDev with circular buffer | -| `_mult` | 8 bytes | Multiplier constant | -| **Total per instance** | **~104 + 2N×8 bytes** | Period-dependent | - -For default N=20: approximately 424 bytes per instance. - ## References - Bollinger, J. (2001). *Bollinger on Bollinger Bands*. McGraw-Hill. (Original Bollinger Band methodology) diff --git a/lib/volatility/bbw/Bbw.Quantower.Tests.cs b/lib/volatility/bbw/tests/Bbw.Quantower.Tests.cs similarity index 100% rename from lib/volatility/bbw/Bbw.Quantower.Tests.cs rename to lib/volatility/bbw/tests/Bbw.Quantower.Tests.cs diff --git a/lib/volatility/bbw/Bbw.Tests.cs b/lib/volatility/bbw/tests/Bbw.Tests.cs similarity index 100% rename from lib/volatility/bbw/Bbw.Tests.cs rename to lib/volatility/bbw/tests/Bbw.Tests.cs diff --git a/lib/volatility/bbw/Bbw.Validation.Tests.cs b/lib/volatility/bbw/tests/Bbw.Validation.Tests.cs similarity index 100% rename from lib/volatility/bbw/Bbw.Validation.Tests.cs rename to lib/volatility/bbw/tests/Bbw.Validation.Tests.cs diff --git a/lib/volatility/bbwn/Bbwn.Quantower.Tests.cs b/lib/volatility/bbwn/tests/Bbwn.Quantower.Tests.cs similarity index 100% rename from lib/volatility/bbwn/Bbwn.Quantower.Tests.cs rename to lib/volatility/bbwn/tests/Bbwn.Quantower.Tests.cs diff --git a/lib/volatility/bbwn/Bbwn.Tests.cs b/lib/volatility/bbwn/tests/Bbwn.Tests.cs similarity index 100% rename from lib/volatility/bbwn/Bbwn.Tests.cs rename to lib/volatility/bbwn/tests/Bbwn.Tests.cs diff --git a/lib/volatility/bbwn/Bbwn.Validation.Tests.cs b/lib/volatility/bbwn/tests/Bbwn.Validation.Tests.cs similarity index 100% rename from lib/volatility/bbwn/Bbwn.Validation.Tests.cs rename to lib/volatility/bbwn/tests/Bbwn.Validation.Tests.cs diff --git a/lib/volatility/bbwp/Bbwp.Quantower.Tests.cs b/lib/volatility/bbwp/tests/Bbwp.Quantower.Tests.cs similarity index 100% rename from lib/volatility/bbwp/Bbwp.Quantower.Tests.cs rename to lib/volatility/bbwp/tests/Bbwp.Quantower.Tests.cs diff --git a/lib/volatility/bbwp/Bbwp.Tests.cs b/lib/volatility/bbwp/tests/Bbwp.Tests.cs similarity index 100% rename from lib/volatility/bbwp/Bbwp.Tests.cs rename to lib/volatility/bbwp/tests/Bbwp.Tests.cs diff --git a/lib/volatility/bbwp/Bbwp.Validation.Tests.cs b/lib/volatility/bbwp/tests/Bbwp.Validation.Tests.cs similarity index 100% rename from lib/volatility/bbwp/Bbwp.Validation.Tests.cs rename to lib/volatility/bbwp/tests/Bbwp.Validation.Tests.cs diff --git a/lib/volatility/ccv/Ccv.Quantower.Tests.cs b/lib/volatility/ccv/tests/Ccv.Quantower.Tests.cs similarity index 100% rename from lib/volatility/ccv/Ccv.Quantower.Tests.cs rename to lib/volatility/ccv/tests/Ccv.Quantower.Tests.cs diff --git a/lib/volatility/ccv/Ccv.Tests.cs b/lib/volatility/ccv/tests/Ccv.Tests.cs similarity index 100% rename from lib/volatility/ccv/Ccv.Tests.cs rename to lib/volatility/ccv/tests/Ccv.Tests.cs diff --git a/lib/volatility/ccv/Ccv.Validation.Tests.cs b/lib/volatility/ccv/tests/Ccv.Validation.Tests.cs similarity index 100% rename from lib/volatility/ccv/Ccv.Validation.Tests.cs rename to lib/volatility/ccv/tests/Ccv.Validation.Tests.cs diff --git a/lib/volatility/cv/Cv.Quantower.Tests.cs b/lib/volatility/cv/tests/Cv.Quantower.Tests.cs similarity index 100% rename from lib/volatility/cv/Cv.Quantower.Tests.cs rename to lib/volatility/cv/tests/Cv.Quantower.Tests.cs diff --git a/lib/volatility/cv/Cv.Tests.cs b/lib/volatility/cv/tests/Cv.Tests.cs similarity index 100% rename from lib/volatility/cv/Cv.Tests.cs rename to lib/volatility/cv/tests/Cv.Tests.cs diff --git a/lib/volatility/cv/Cv.Validation.Tests.cs b/lib/volatility/cv/tests/Cv.Validation.Tests.cs similarity index 100% rename from lib/volatility/cv/Cv.Validation.Tests.cs rename to lib/volatility/cv/tests/Cv.Validation.Tests.cs diff --git a/lib/volatility/cvi/Cvi.Quantower.Tests.cs b/lib/volatility/cvi/tests/Cvi.Quantower.Tests.cs similarity index 100% rename from lib/volatility/cvi/Cvi.Quantower.Tests.cs rename to lib/volatility/cvi/tests/Cvi.Quantower.Tests.cs diff --git a/lib/volatility/cvi/Cvi.Tests.cs b/lib/volatility/cvi/tests/Cvi.Tests.cs similarity index 100% rename from lib/volatility/cvi/Cvi.Tests.cs rename to lib/volatility/cvi/tests/Cvi.Tests.cs diff --git a/lib/volatility/cvi/Cvi.Validation.Tests.cs b/lib/volatility/cvi/tests/Cvi.Validation.Tests.cs similarity index 100% rename from lib/volatility/cvi/Cvi.Validation.Tests.cs rename to lib/volatility/cvi/tests/Cvi.Validation.Tests.cs diff --git a/lib/volatility/etherm/Etherm.Quantower.Tests.cs b/lib/volatility/etherm/tests/Etherm.Quantower.Tests.cs similarity index 100% rename from lib/volatility/etherm/Etherm.Quantower.Tests.cs rename to lib/volatility/etherm/tests/Etherm.Quantower.Tests.cs diff --git a/lib/volatility/etherm/Etherm.Tests.cs b/lib/volatility/etherm/tests/Etherm.Tests.cs similarity index 100% rename from lib/volatility/etherm/Etherm.Tests.cs rename to lib/volatility/etherm/tests/Etherm.Tests.cs diff --git a/lib/volatility/etherm/Etherm.Validation.Tests.cs b/lib/volatility/etherm/tests/Etherm.Validation.Tests.cs similarity index 100% rename from lib/volatility/etherm/Etherm.Validation.Tests.cs rename to lib/volatility/etherm/tests/Etherm.Validation.Tests.cs diff --git a/lib/volatility/ewma/Ewma.Quantower.Tests.cs b/lib/volatility/ewma/tests/Ewma.Quantower.Tests.cs similarity index 100% rename from lib/volatility/ewma/Ewma.Quantower.Tests.cs rename to lib/volatility/ewma/tests/Ewma.Quantower.Tests.cs diff --git a/lib/volatility/ewma/Ewma.Tests.cs b/lib/volatility/ewma/tests/Ewma.Tests.cs similarity index 100% rename from lib/volatility/ewma/Ewma.Tests.cs rename to lib/volatility/ewma/tests/Ewma.Tests.cs diff --git a/lib/volatility/ewma/Ewma.Validation.Tests.cs b/lib/volatility/ewma/tests/Ewma.Validation.Tests.cs similarity index 100% rename from lib/volatility/ewma/Ewma.Validation.Tests.cs rename to lib/volatility/ewma/tests/Ewma.Validation.Tests.cs diff --git a/lib/volatility/gkv/Gkv.Quantower.Tests.cs b/lib/volatility/gkv/tests/Gkv.Quantower.Tests.cs similarity index 100% rename from lib/volatility/gkv/Gkv.Quantower.Tests.cs rename to lib/volatility/gkv/tests/Gkv.Quantower.Tests.cs diff --git a/lib/volatility/gkv/Gkv.Tests.cs b/lib/volatility/gkv/tests/Gkv.Tests.cs similarity index 100% rename from lib/volatility/gkv/Gkv.Tests.cs rename to lib/volatility/gkv/tests/Gkv.Tests.cs diff --git a/lib/volatility/gkv/Gkv.Validation.Tests.cs b/lib/volatility/gkv/tests/Gkv.Validation.Tests.cs similarity index 100% rename from lib/volatility/gkv/Gkv.Validation.Tests.cs rename to lib/volatility/gkv/tests/Gkv.Validation.Tests.cs diff --git a/lib/volatility/hlv/Hlv.Quantower.Tests.cs b/lib/volatility/hlv/tests/Hlv.Quantower.Tests.cs similarity index 100% rename from lib/volatility/hlv/Hlv.Quantower.Tests.cs rename to lib/volatility/hlv/tests/Hlv.Quantower.Tests.cs diff --git a/lib/volatility/hlv/Hlv.Tests.cs b/lib/volatility/hlv/tests/Hlv.Tests.cs similarity index 100% rename from lib/volatility/hlv/Hlv.Tests.cs rename to lib/volatility/hlv/tests/Hlv.Tests.cs diff --git a/lib/volatility/hlv/Hlv.Validation.Tests.cs b/lib/volatility/hlv/tests/Hlv.Validation.Tests.cs similarity index 100% rename from lib/volatility/hlv/Hlv.Validation.Tests.cs rename to lib/volatility/hlv/tests/Hlv.Validation.Tests.cs diff --git a/lib/volatility/hv/Hv.Quantower.Tests.cs b/lib/volatility/hv/tests/Hv.Quantower.Tests.cs similarity index 100% rename from lib/volatility/hv/Hv.Quantower.Tests.cs rename to lib/volatility/hv/tests/Hv.Quantower.Tests.cs diff --git a/lib/volatility/hv/Hv.Tests.cs b/lib/volatility/hv/tests/Hv.Tests.cs similarity index 100% rename from lib/volatility/hv/Hv.Tests.cs rename to lib/volatility/hv/tests/Hv.Tests.cs diff --git a/lib/volatility/hv/Hv.Validation.Tests.cs b/lib/volatility/hv/tests/Hv.Validation.Tests.cs similarity index 100% rename from lib/volatility/hv/Hv.Validation.Tests.cs rename to lib/volatility/hv/tests/Hv.Validation.Tests.cs diff --git a/lib/volatility/jvolty/Jvolty.Quantower.Tests.cs b/lib/volatility/jvolty/tests/Jvolty.Quantower.Tests.cs similarity index 100% rename from lib/volatility/jvolty/Jvolty.Quantower.Tests.cs rename to lib/volatility/jvolty/tests/Jvolty.Quantower.Tests.cs diff --git a/lib/volatility/jvolty/Jvolty.Tests.cs b/lib/volatility/jvolty/tests/Jvolty.Tests.cs similarity index 100% rename from lib/volatility/jvolty/Jvolty.Tests.cs rename to lib/volatility/jvolty/tests/Jvolty.Tests.cs diff --git a/lib/volatility/jvolty/Jvolty.Validation.Tests.cs b/lib/volatility/jvolty/tests/Jvolty.Validation.Tests.cs similarity index 100% rename from lib/volatility/jvolty/Jvolty.Validation.Tests.cs rename to lib/volatility/jvolty/tests/Jvolty.Validation.Tests.cs diff --git a/lib/volatility/jvoltyn/Jvoltyn.Quantower.Tests.cs b/lib/volatility/jvoltyn/tests/Jvoltyn.Quantower.Tests.cs similarity index 100% rename from lib/volatility/jvoltyn/Jvoltyn.Quantower.Tests.cs rename to lib/volatility/jvoltyn/tests/Jvoltyn.Quantower.Tests.cs diff --git a/lib/volatility/jvoltyn/Jvoltyn.Tests.cs b/lib/volatility/jvoltyn/tests/Jvoltyn.Tests.cs similarity index 100% rename from lib/volatility/jvoltyn/Jvoltyn.Tests.cs rename to lib/volatility/jvoltyn/tests/Jvoltyn.Tests.cs diff --git a/lib/volatility/jvoltyn/Jvoltyn.Validation.Tests.cs b/lib/volatility/jvoltyn/tests/Jvoltyn.Validation.Tests.cs similarity index 100% rename from lib/volatility/jvoltyn/Jvoltyn.Validation.Tests.cs rename to lib/volatility/jvoltyn/tests/Jvoltyn.Validation.Tests.cs diff --git a/lib/volatility/massi/Massi.Quantower.Tests.cs b/lib/volatility/massi/tests/Massi.Quantower.Tests.cs similarity index 100% rename from lib/volatility/massi/Massi.Quantower.Tests.cs rename to lib/volatility/massi/tests/Massi.Quantower.Tests.cs diff --git a/lib/volatility/massi/Massi.Tests.cs b/lib/volatility/massi/tests/Massi.Tests.cs similarity index 100% rename from lib/volatility/massi/Massi.Tests.cs rename to lib/volatility/massi/tests/Massi.Tests.cs diff --git a/lib/volatility/massi/Massi.Validation.Tests.cs b/lib/volatility/massi/tests/Massi.Validation.Tests.cs similarity index 100% rename from lib/volatility/massi/Massi.Validation.Tests.cs rename to lib/volatility/massi/tests/Massi.Validation.Tests.cs diff --git a/lib/volatility/natr/Natr.Quantower.Tests.cs b/lib/volatility/natr/tests/Natr.Quantower.Tests.cs similarity index 100% rename from lib/volatility/natr/Natr.Quantower.Tests.cs rename to lib/volatility/natr/tests/Natr.Quantower.Tests.cs diff --git a/lib/volatility/natr/Natr.Tests.cs b/lib/volatility/natr/tests/Natr.Tests.cs similarity index 100% rename from lib/volatility/natr/Natr.Tests.cs rename to lib/volatility/natr/tests/Natr.Tests.cs diff --git a/lib/volatility/natr/Natr.Validation.Tests.cs b/lib/volatility/natr/tests/Natr.Validation.Tests.cs similarity index 100% rename from lib/volatility/natr/Natr.Validation.Tests.cs rename to lib/volatility/natr/tests/Natr.Validation.Tests.cs diff --git a/lib/volatility/rsv/Rsv.Quantower.Tests.cs b/lib/volatility/rsv/tests/Rsv.Quantower.Tests.cs similarity index 100% rename from lib/volatility/rsv/Rsv.Quantower.Tests.cs rename to lib/volatility/rsv/tests/Rsv.Quantower.Tests.cs diff --git a/lib/volatility/rsv/Rsv.Tests.cs b/lib/volatility/rsv/tests/Rsv.Tests.cs similarity index 100% rename from lib/volatility/rsv/Rsv.Tests.cs rename to lib/volatility/rsv/tests/Rsv.Tests.cs diff --git a/lib/volatility/rsv/Rsv.Validation.Tests.cs b/lib/volatility/rsv/tests/Rsv.Validation.Tests.cs similarity index 100% rename from lib/volatility/rsv/Rsv.Validation.Tests.cs rename to lib/volatility/rsv/tests/Rsv.Validation.Tests.cs diff --git a/lib/volatility/rv/Rv.Quantower.Tests.cs b/lib/volatility/rv/tests/Rv.Quantower.Tests.cs similarity index 100% rename from lib/volatility/rv/Rv.Quantower.Tests.cs rename to lib/volatility/rv/tests/Rv.Quantower.Tests.cs diff --git a/lib/volatility/rv/Rv.Tests.cs b/lib/volatility/rv/tests/Rv.Tests.cs similarity index 100% rename from lib/volatility/rv/Rv.Tests.cs rename to lib/volatility/rv/tests/Rv.Tests.cs diff --git a/lib/volatility/rv/Rv.Validation.Tests.cs b/lib/volatility/rv/tests/Rv.Validation.Tests.cs similarity index 100% rename from lib/volatility/rv/Rv.Validation.Tests.cs rename to lib/volatility/rv/tests/Rv.Validation.Tests.cs diff --git a/lib/volatility/rvi/Rvi.Quantower.Tests.cs b/lib/volatility/rvi/tests/Rvi.Quantower.Tests.cs similarity index 100% rename from lib/volatility/rvi/Rvi.Quantower.Tests.cs rename to lib/volatility/rvi/tests/Rvi.Quantower.Tests.cs diff --git a/lib/volatility/rvi/Rvi.Tests.cs b/lib/volatility/rvi/tests/Rvi.Tests.cs similarity index 100% rename from lib/volatility/rvi/Rvi.Tests.cs rename to lib/volatility/rvi/tests/Rvi.Tests.cs diff --git a/lib/volatility/rvi/Rvi.Validation.Tests.cs b/lib/volatility/rvi/tests/Rvi.Validation.Tests.cs similarity index 100% rename from lib/volatility/rvi/Rvi.Validation.Tests.cs rename to lib/volatility/rvi/tests/Rvi.Validation.Tests.cs diff --git a/lib/volatility/tr/Tr.Quantower.Tests.cs b/lib/volatility/tr/tests/Tr.Quantower.Tests.cs similarity index 100% rename from lib/volatility/tr/Tr.Quantower.Tests.cs rename to lib/volatility/tr/tests/Tr.Quantower.Tests.cs diff --git a/lib/volatility/tr/Tr.Tests.cs b/lib/volatility/tr/tests/Tr.Tests.cs similarity index 100% rename from lib/volatility/tr/Tr.Tests.cs rename to lib/volatility/tr/tests/Tr.Tests.cs diff --git a/lib/volatility/tr/Tr.Validation.Tests.cs b/lib/volatility/tr/tests/Tr.Validation.Tests.cs similarity index 100% rename from lib/volatility/tr/Tr.Validation.Tests.cs rename to lib/volatility/tr/tests/Tr.Validation.Tests.cs diff --git a/lib/volatility/ui/Ui.Quantower.Tests.cs b/lib/volatility/ui/tests/Ui.Quantower.Tests.cs similarity index 100% rename from lib/volatility/ui/Ui.Quantower.Tests.cs rename to lib/volatility/ui/tests/Ui.Quantower.Tests.cs diff --git a/lib/volatility/ui/Ui.Tests.cs b/lib/volatility/ui/tests/Ui.Tests.cs similarity index 100% rename from lib/volatility/ui/Ui.Tests.cs rename to lib/volatility/ui/tests/Ui.Tests.cs diff --git a/lib/volatility/ui/Ui.Validation.Tests.cs b/lib/volatility/ui/tests/Ui.Validation.Tests.cs similarity index 100% rename from lib/volatility/ui/Ui.Validation.Tests.cs rename to lib/volatility/ui/tests/Ui.Validation.Tests.cs diff --git a/lib/volatility/vov/Vov.Quantower.Tests.cs b/lib/volatility/vov/tests/Vov.Quantower.Tests.cs similarity index 100% rename from lib/volatility/vov/Vov.Quantower.Tests.cs rename to lib/volatility/vov/tests/Vov.Quantower.Tests.cs diff --git a/lib/volatility/vov/Vov.Tests.cs b/lib/volatility/vov/tests/Vov.Tests.cs similarity index 100% rename from lib/volatility/vov/Vov.Tests.cs rename to lib/volatility/vov/tests/Vov.Tests.cs diff --git a/lib/volatility/vov/Vov.Validation.Tests.cs b/lib/volatility/vov/tests/Vov.Validation.Tests.cs similarity index 100% rename from lib/volatility/vov/Vov.Validation.Tests.cs rename to lib/volatility/vov/tests/Vov.Validation.Tests.cs diff --git a/lib/volatility/vr/Vr.Quantower.Tests.cs b/lib/volatility/vr/tests/Vr.Quantower.Tests.cs similarity index 100% rename from lib/volatility/vr/Vr.Quantower.Tests.cs rename to lib/volatility/vr/tests/Vr.Quantower.Tests.cs diff --git a/lib/volatility/vr/Vr.Tests.cs b/lib/volatility/vr/tests/Vr.Tests.cs similarity index 100% rename from lib/volatility/vr/Vr.Tests.cs rename to lib/volatility/vr/tests/Vr.Tests.cs diff --git a/lib/volatility/vr/Vr.Validation.Tests.cs b/lib/volatility/vr/tests/Vr.Validation.Tests.cs similarity index 100% rename from lib/volatility/vr/Vr.Validation.Tests.cs rename to lib/volatility/vr/tests/Vr.Validation.Tests.cs diff --git a/lib/volatility/yzv/Yzv.Quantower.Tests.cs b/lib/volatility/yzv/tests/Yzv.Quantower.Tests.cs similarity index 100% rename from lib/volatility/yzv/Yzv.Quantower.Tests.cs rename to lib/volatility/yzv/tests/Yzv.Quantower.Tests.cs diff --git a/lib/volatility/yzv/Yzv.Tests.cs b/lib/volatility/yzv/tests/Yzv.Tests.cs similarity index 100% rename from lib/volatility/yzv/Yzv.Tests.cs rename to lib/volatility/yzv/tests/Yzv.Tests.cs diff --git a/lib/volatility/yzv/Yzv.Validation.Tests.cs b/lib/volatility/yzv/tests/Yzv.Validation.Tests.cs similarity index 100% rename from lib/volatility/yzv/Yzv.Validation.Tests.cs rename to lib/volatility/yzv/tests/Yzv.Validation.Tests.cs diff --git a/lib/volume/adl/Adl.Quantower.Tests.cs b/lib/volume/adl/tests/Adl.Quantower.Tests.cs similarity index 100% rename from lib/volume/adl/Adl.Quantower.Tests.cs rename to lib/volume/adl/tests/Adl.Quantower.Tests.cs diff --git a/lib/volume/adl/Adl.Tests.cs b/lib/volume/adl/tests/Adl.Tests.cs similarity index 100% rename from lib/volume/adl/Adl.Tests.cs rename to lib/volume/adl/tests/Adl.Tests.cs diff --git a/lib/volume/adl/Adl.Validation.Tests.cs b/lib/volume/adl/tests/Adl.Validation.Tests.cs similarity index 100% rename from lib/volume/adl/Adl.Validation.Tests.cs rename to lib/volume/adl/tests/Adl.Validation.Tests.cs diff --git a/lib/volume/adosc/Adosc.Quantower.Tests.cs b/lib/volume/adosc/tests/Adosc.Quantower.Tests.cs similarity index 100% rename from lib/volume/adosc/Adosc.Quantower.Tests.cs rename to lib/volume/adosc/tests/Adosc.Quantower.Tests.cs diff --git a/lib/volume/adosc/Adosc.Tests.cs b/lib/volume/adosc/tests/Adosc.Tests.cs similarity index 100% rename from lib/volume/adosc/Adosc.Tests.cs rename to lib/volume/adosc/tests/Adosc.Tests.cs diff --git a/lib/volume/adosc/Adosc.Validation.Tests.cs b/lib/volume/adosc/tests/Adosc.Validation.Tests.cs similarity index 100% rename from lib/volume/adosc/Adosc.Validation.Tests.cs rename to lib/volume/adosc/tests/Adosc.Validation.Tests.cs diff --git a/lib/volume/aobv/Aobv.Quantower.Tests.cs b/lib/volume/aobv/tests/Aobv.Quantower.Tests.cs similarity index 100% rename from lib/volume/aobv/Aobv.Quantower.Tests.cs rename to lib/volume/aobv/tests/Aobv.Quantower.Tests.cs diff --git a/lib/volume/aobv/Aobv.Tests.cs b/lib/volume/aobv/tests/Aobv.Tests.cs similarity index 100% rename from lib/volume/aobv/Aobv.Tests.cs rename to lib/volume/aobv/tests/Aobv.Tests.cs diff --git a/lib/volume/aobv/Aobv.Validation.Tests.cs b/lib/volume/aobv/tests/Aobv.Validation.Tests.cs similarity index 100% rename from lib/volume/aobv/Aobv.Validation.Tests.cs rename to lib/volume/aobv/tests/Aobv.Validation.Tests.cs diff --git a/lib/volume/cmf/Cmf.Quantower.Tests.cs b/lib/volume/cmf/tests/Cmf.Quantower.Tests.cs similarity index 100% rename from lib/volume/cmf/Cmf.Quantower.Tests.cs rename to lib/volume/cmf/tests/Cmf.Quantower.Tests.cs diff --git a/lib/volume/cmf/Cmf.Tests.cs b/lib/volume/cmf/tests/Cmf.Tests.cs similarity index 100% rename from lib/volume/cmf/Cmf.Tests.cs rename to lib/volume/cmf/tests/Cmf.Tests.cs diff --git a/lib/volume/cmf/Cmf.Validation.Tests.cs b/lib/volume/cmf/tests/Cmf.Validation.Tests.cs similarity index 100% rename from lib/volume/cmf/Cmf.Validation.Tests.cs rename to lib/volume/cmf/tests/Cmf.Validation.Tests.cs diff --git a/lib/volume/efi/Efi.Quantower.Tests.cs b/lib/volume/efi/tests/Efi.Quantower.Tests.cs similarity index 100% rename from lib/volume/efi/Efi.Quantower.Tests.cs rename to lib/volume/efi/tests/Efi.Quantower.Tests.cs diff --git a/lib/volume/efi/Efi.Tests.cs b/lib/volume/efi/tests/Efi.Tests.cs similarity index 100% rename from lib/volume/efi/Efi.Tests.cs rename to lib/volume/efi/tests/Efi.Tests.cs diff --git a/lib/volume/efi/Efi.Validation.Tests.cs b/lib/volume/efi/tests/Efi.Validation.Tests.cs similarity index 100% rename from lib/volume/efi/Efi.Validation.Tests.cs rename to lib/volume/efi/tests/Efi.Validation.Tests.cs diff --git a/lib/volume/eom/Eom.Quantower.Tests.cs b/lib/volume/eom/tests/Eom.Quantower.Tests.cs similarity index 100% rename from lib/volume/eom/Eom.Quantower.Tests.cs rename to lib/volume/eom/tests/Eom.Quantower.Tests.cs diff --git a/lib/volume/eom/Eom.Tests.cs b/lib/volume/eom/tests/Eom.Tests.cs similarity index 100% rename from lib/volume/eom/Eom.Tests.cs rename to lib/volume/eom/tests/Eom.Tests.cs diff --git a/lib/volume/eom/Eom.Validation.Tests.cs b/lib/volume/eom/tests/Eom.Validation.Tests.cs similarity index 100% rename from lib/volume/eom/Eom.Validation.Tests.cs rename to lib/volume/eom/tests/Eom.Validation.Tests.cs diff --git a/lib/volume/evwma/Evwma.Quantower.Tests.cs b/lib/volume/evwma/tests/Evwma.Quantower.Tests.cs similarity index 100% rename from lib/volume/evwma/Evwma.Quantower.Tests.cs rename to lib/volume/evwma/tests/Evwma.Quantower.Tests.cs diff --git a/lib/volume/evwma/Evwma.Tests.cs b/lib/volume/evwma/tests/Evwma.Tests.cs similarity index 100% rename from lib/volume/evwma/Evwma.Tests.cs rename to lib/volume/evwma/tests/Evwma.Tests.cs diff --git a/lib/volume/evwma/Evwma.Validation.Tests.cs b/lib/volume/evwma/tests/Evwma.Validation.Tests.cs similarity index 100% rename from lib/volume/evwma/Evwma.Validation.Tests.cs rename to lib/volume/evwma/tests/Evwma.Validation.Tests.cs diff --git a/lib/volume/iii/Iii.Quantower.Tests.cs b/lib/volume/iii/tests/Iii.Quantower.Tests.cs similarity index 100% rename from lib/volume/iii/Iii.Quantower.Tests.cs rename to lib/volume/iii/tests/Iii.Quantower.Tests.cs diff --git a/lib/volume/iii/Iii.Tests.cs b/lib/volume/iii/tests/Iii.Tests.cs similarity index 100% rename from lib/volume/iii/Iii.Tests.cs rename to lib/volume/iii/tests/Iii.Tests.cs diff --git a/lib/volume/iii/Iii.Validation.Tests.cs b/lib/volume/iii/tests/Iii.Validation.Tests.cs similarity index 100% rename from lib/volume/iii/Iii.Validation.Tests.cs rename to lib/volume/iii/tests/Iii.Validation.Tests.cs diff --git a/lib/volume/kvo/Kvo.Quantower.Tests.cs b/lib/volume/kvo/tests/Kvo.Quantower.Tests.cs similarity index 100% rename from lib/volume/kvo/Kvo.Quantower.Tests.cs rename to lib/volume/kvo/tests/Kvo.Quantower.Tests.cs diff --git a/lib/volume/kvo/Kvo.Tests.cs b/lib/volume/kvo/tests/Kvo.Tests.cs similarity index 100% rename from lib/volume/kvo/Kvo.Tests.cs rename to lib/volume/kvo/tests/Kvo.Tests.cs diff --git a/lib/volume/kvo/Kvo.Validation.Tests.cs b/lib/volume/kvo/tests/Kvo.Validation.Tests.cs similarity index 100% rename from lib/volume/kvo/Kvo.Validation.Tests.cs rename to lib/volume/kvo/tests/Kvo.Validation.Tests.cs diff --git a/lib/volume/mfi/Mfi.Quantower.Tests.cs b/lib/volume/mfi/tests/Mfi.Quantower.Tests.cs similarity index 100% rename from lib/volume/mfi/Mfi.Quantower.Tests.cs rename to lib/volume/mfi/tests/Mfi.Quantower.Tests.cs diff --git a/lib/volume/mfi/Mfi.Tests.cs b/lib/volume/mfi/tests/Mfi.Tests.cs similarity index 100% rename from lib/volume/mfi/Mfi.Tests.cs rename to lib/volume/mfi/tests/Mfi.Tests.cs diff --git a/lib/volume/mfi/Mfi.Validation.Tests.cs b/lib/volume/mfi/tests/Mfi.Validation.Tests.cs similarity index 100% rename from lib/volume/mfi/Mfi.Validation.Tests.cs rename to lib/volume/mfi/tests/Mfi.Validation.Tests.cs diff --git a/lib/volume/nvi/Nvi.Quantower.Tests.cs b/lib/volume/nvi/tests/Nvi.Quantower.Tests.cs similarity index 100% rename from lib/volume/nvi/Nvi.Quantower.Tests.cs rename to lib/volume/nvi/tests/Nvi.Quantower.Tests.cs diff --git a/lib/volume/nvi/Nvi.Tests.cs b/lib/volume/nvi/tests/Nvi.Tests.cs similarity index 100% rename from lib/volume/nvi/Nvi.Tests.cs rename to lib/volume/nvi/tests/Nvi.Tests.cs diff --git a/lib/volume/nvi/Nvi.Validation.Tests.cs b/lib/volume/nvi/tests/Nvi.Validation.Tests.cs similarity index 100% rename from lib/volume/nvi/Nvi.Validation.Tests.cs rename to lib/volume/nvi/tests/Nvi.Validation.Tests.cs diff --git a/lib/volume/obv/Obv.Quantower.Tests.cs b/lib/volume/obv/tests/Obv.Quantower.Tests.cs similarity index 100% rename from lib/volume/obv/Obv.Quantower.Tests.cs rename to lib/volume/obv/tests/Obv.Quantower.Tests.cs diff --git a/lib/volume/obv/Obv.Tests.cs b/lib/volume/obv/tests/Obv.Tests.cs similarity index 100% rename from lib/volume/obv/Obv.Tests.cs rename to lib/volume/obv/tests/Obv.Tests.cs diff --git a/lib/volume/obv/Obv.Validation.Tests.cs b/lib/volume/obv/tests/Obv.Validation.Tests.cs similarity index 100% rename from lib/volume/obv/Obv.Validation.Tests.cs rename to lib/volume/obv/tests/Obv.Validation.Tests.cs diff --git a/lib/volume/pvd/Pvd.Quantower.Tests.cs b/lib/volume/pvd/tests/Pvd.Quantower.Tests.cs similarity index 100% rename from lib/volume/pvd/Pvd.Quantower.Tests.cs rename to lib/volume/pvd/tests/Pvd.Quantower.Tests.cs diff --git a/lib/volume/pvd/Pvd.Tests.cs b/lib/volume/pvd/tests/Pvd.Tests.cs similarity index 100% rename from lib/volume/pvd/Pvd.Tests.cs rename to lib/volume/pvd/tests/Pvd.Tests.cs diff --git a/lib/volume/pvd/Pvd.Validation.Tests.cs b/lib/volume/pvd/tests/Pvd.Validation.Tests.cs similarity index 100% rename from lib/volume/pvd/Pvd.Validation.Tests.cs rename to lib/volume/pvd/tests/Pvd.Validation.Tests.cs diff --git a/lib/volume/pvi/Pvi.Quantower.Tests.cs b/lib/volume/pvi/tests/Pvi.Quantower.Tests.cs similarity index 100% rename from lib/volume/pvi/Pvi.Quantower.Tests.cs rename to lib/volume/pvi/tests/Pvi.Quantower.Tests.cs diff --git a/lib/volume/pvi/Pvi.Tests.cs b/lib/volume/pvi/tests/Pvi.Tests.cs similarity index 100% rename from lib/volume/pvi/Pvi.Tests.cs rename to lib/volume/pvi/tests/Pvi.Tests.cs diff --git a/lib/volume/pvi/Pvi.Validation.Tests.cs b/lib/volume/pvi/tests/Pvi.Validation.Tests.cs similarity index 100% rename from lib/volume/pvi/Pvi.Validation.Tests.cs rename to lib/volume/pvi/tests/Pvi.Validation.Tests.cs diff --git a/lib/volume/pvo/Pvo.Quantower.Tests.cs b/lib/volume/pvo/tests/Pvo.Quantower.Tests.cs similarity index 100% rename from lib/volume/pvo/Pvo.Quantower.Tests.cs rename to lib/volume/pvo/tests/Pvo.Quantower.Tests.cs diff --git a/lib/volume/pvo/Pvo.Tests.cs b/lib/volume/pvo/tests/Pvo.Tests.cs similarity index 100% rename from lib/volume/pvo/Pvo.Tests.cs rename to lib/volume/pvo/tests/Pvo.Tests.cs diff --git a/lib/volume/pvo/Pvo.Validation.Tests.cs b/lib/volume/pvo/tests/Pvo.Validation.Tests.cs similarity index 100% rename from lib/volume/pvo/Pvo.Validation.Tests.cs rename to lib/volume/pvo/tests/Pvo.Validation.Tests.cs diff --git a/lib/volume/pvr/Pvr.Quantower.Tests.cs b/lib/volume/pvr/tests/Pvr.Quantower.Tests.cs similarity index 100% rename from lib/volume/pvr/Pvr.Quantower.Tests.cs rename to lib/volume/pvr/tests/Pvr.Quantower.Tests.cs diff --git a/lib/volume/pvr/Pvr.Tests.cs b/lib/volume/pvr/tests/Pvr.Tests.cs similarity index 100% rename from lib/volume/pvr/Pvr.Tests.cs rename to lib/volume/pvr/tests/Pvr.Tests.cs diff --git a/lib/volume/pvr/Pvr.Validation.Tests.cs b/lib/volume/pvr/tests/Pvr.Validation.Tests.cs similarity index 100% rename from lib/volume/pvr/Pvr.Validation.Tests.cs rename to lib/volume/pvr/tests/Pvr.Validation.Tests.cs diff --git a/lib/volume/pvt/Pvt.Quantower.Tests.cs b/lib/volume/pvt/tests/Pvt.Quantower.Tests.cs similarity index 100% rename from lib/volume/pvt/Pvt.Quantower.Tests.cs rename to lib/volume/pvt/tests/Pvt.Quantower.Tests.cs diff --git a/lib/volume/pvt/Pvt.Tests.cs b/lib/volume/pvt/tests/Pvt.Tests.cs similarity index 100% rename from lib/volume/pvt/Pvt.Tests.cs rename to lib/volume/pvt/tests/Pvt.Tests.cs diff --git a/lib/volume/pvt/Pvt.Validation.Tests.cs b/lib/volume/pvt/tests/Pvt.Validation.Tests.cs similarity index 100% rename from lib/volume/pvt/Pvt.Validation.Tests.cs rename to lib/volume/pvt/tests/Pvt.Validation.Tests.cs diff --git a/lib/volume/tvi/Tvi.Quantower.Tests.cs b/lib/volume/tvi/tests/Tvi.Quantower.Tests.cs similarity index 100% rename from lib/volume/tvi/Tvi.Quantower.Tests.cs rename to lib/volume/tvi/tests/Tvi.Quantower.Tests.cs diff --git a/lib/volume/tvi/Tvi.Tests.cs b/lib/volume/tvi/tests/Tvi.Tests.cs similarity index 100% rename from lib/volume/tvi/Tvi.Tests.cs rename to lib/volume/tvi/tests/Tvi.Tests.cs diff --git a/lib/volume/tvi/Tvi.Validation.Tests.cs b/lib/volume/tvi/tests/Tvi.Validation.Tests.cs similarity index 100% rename from lib/volume/tvi/Tvi.Validation.Tests.cs rename to lib/volume/tvi/tests/Tvi.Validation.Tests.cs diff --git a/lib/volume/twap/Twap.Quantower.Tests.cs b/lib/volume/twap/tests/Twap.Quantower.Tests.cs similarity index 100% rename from lib/volume/twap/Twap.Quantower.Tests.cs rename to lib/volume/twap/tests/Twap.Quantower.Tests.cs diff --git a/lib/volume/twap/Twap.Tests.cs b/lib/volume/twap/tests/Twap.Tests.cs similarity index 100% rename from lib/volume/twap/Twap.Tests.cs rename to lib/volume/twap/tests/Twap.Tests.cs diff --git a/lib/volume/twap/Twap.Validation.Tests.cs b/lib/volume/twap/tests/Twap.Validation.Tests.cs similarity index 100% rename from lib/volume/twap/Twap.Validation.Tests.cs rename to lib/volume/twap/tests/Twap.Validation.Tests.cs diff --git a/lib/volume/va/Va.Quantower.Tests.cs b/lib/volume/va/tests/Va.Quantower.Tests.cs similarity index 100% rename from lib/volume/va/Va.Quantower.Tests.cs rename to lib/volume/va/tests/Va.Quantower.Tests.cs diff --git a/lib/volume/va/Va.Tests.cs b/lib/volume/va/tests/Va.Tests.cs similarity index 100% rename from lib/volume/va/Va.Tests.cs rename to lib/volume/va/tests/Va.Tests.cs diff --git a/lib/volume/va/Va.Validation.Tests.cs b/lib/volume/va/tests/Va.Validation.Tests.cs similarity index 100% rename from lib/volume/va/Va.Validation.Tests.cs rename to lib/volume/va/tests/Va.Validation.Tests.cs diff --git a/lib/volume/vf/Vf.Quantower.Tests.cs b/lib/volume/vf/tests/Vf.Quantower.Tests.cs similarity index 100% rename from lib/volume/vf/Vf.Quantower.Tests.cs rename to lib/volume/vf/tests/Vf.Quantower.Tests.cs diff --git a/lib/volume/vf/Vf.Tests.cs b/lib/volume/vf/tests/Vf.Tests.cs similarity index 100% rename from lib/volume/vf/Vf.Tests.cs rename to lib/volume/vf/tests/Vf.Tests.cs diff --git a/lib/volume/vf/Vf.Validation.Tests.cs b/lib/volume/vf/tests/Vf.Validation.Tests.cs similarity index 100% rename from lib/volume/vf/Vf.Validation.Tests.cs rename to lib/volume/vf/tests/Vf.Validation.Tests.cs diff --git a/lib/volume/vo/Vo.Quantower.Tests.cs b/lib/volume/vo/tests/Vo.Quantower.Tests.cs similarity index 100% rename from lib/volume/vo/Vo.Quantower.Tests.cs rename to lib/volume/vo/tests/Vo.Quantower.Tests.cs diff --git a/lib/volume/vo/Vo.Tests.cs b/lib/volume/vo/tests/Vo.Tests.cs similarity index 100% rename from lib/volume/vo/Vo.Tests.cs rename to lib/volume/vo/tests/Vo.Tests.cs diff --git a/lib/volume/vo/Vo.Validation.Tests.cs b/lib/volume/vo/tests/Vo.Validation.Tests.cs similarity index 100% rename from lib/volume/vo/Vo.Validation.Tests.cs rename to lib/volume/vo/tests/Vo.Validation.Tests.cs diff --git a/lib/volume/vroc/Vroc.Quantower.Tests.cs b/lib/volume/vroc/tests/Vroc.Quantower.Tests.cs similarity index 100% rename from lib/volume/vroc/Vroc.Quantower.Tests.cs rename to lib/volume/vroc/tests/Vroc.Quantower.Tests.cs diff --git a/lib/volume/vroc/Vroc.Tests.cs b/lib/volume/vroc/tests/Vroc.Tests.cs similarity index 100% rename from lib/volume/vroc/Vroc.Tests.cs rename to lib/volume/vroc/tests/Vroc.Tests.cs diff --git a/lib/volume/vroc/Vroc.Validation.Tests.cs b/lib/volume/vroc/tests/Vroc.Validation.Tests.cs similarity index 100% rename from lib/volume/vroc/Vroc.Validation.Tests.cs rename to lib/volume/vroc/tests/Vroc.Validation.Tests.cs diff --git a/lib/volume/vwad/Vwad.Quantower.Tests.cs b/lib/volume/vwad/tests/Vwad.Quantower.Tests.cs similarity index 100% rename from lib/volume/vwad/Vwad.Quantower.Tests.cs rename to lib/volume/vwad/tests/Vwad.Quantower.Tests.cs diff --git a/lib/volume/vwad/Vwad.Tests.cs b/lib/volume/vwad/tests/Vwad.Tests.cs similarity index 100% rename from lib/volume/vwad/Vwad.Tests.cs rename to lib/volume/vwad/tests/Vwad.Tests.cs diff --git a/lib/volume/vwad/Vwad.Validation.Tests.cs b/lib/volume/vwad/tests/Vwad.Validation.Tests.cs similarity index 100% rename from lib/volume/vwad/Vwad.Validation.Tests.cs rename to lib/volume/vwad/tests/Vwad.Validation.Tests.cs diff --git a/lib/volume/vwap/Vwap.Quantower.Tests.cs b/lib/volume/vwap/tests/Vwap.Quantower.Tests.cs similarity index 100% rename from lib/volume/vwap/Vwap.Quantower.Tests.cs rename to lib/volume/vwap/tests/Vwap.Quantower.Tests.cs diff --git a/lib/volume/vwap/Vwap.Tests.cs b/lib/volume/vwap/tests/Vwap.Tests.cs similarity index 100% rename from lib/volume/vwap/Vwap.Tests.cs rename to lib/volume/vwap/tests/Vwap.Tests.cs diff --git a/lib/volume/vwap/Vwap.Validation.Tests.cs b/lib/volume/vwap/tests/Vwap.Validation.Tests.cs similarity index 100% rename from lib/volume/vwap/Vwap.Validation.Tests.cs rename to lib/volume/vwap/tests/Vwap.Validation.Tests.cs diff --git a/lib/volume/vwma/Vwma.Quantower.Tests.cs b/lib/volume/vwma/tests/Vwma.Quantower.Tests.cs similarity index 100% rename from lib/volume/vwma/Vwma.Quantower.Tests.cs rename to lib/volume/vwma/tests/Vwma.Quantower.Tests.cs diff --git a/lib/volume/vwma/Vwma.Tests.cs b/lib/volume/vwma/tests/Vwma.Tests.cs similarity index 100% rename from lib/volume/vwma/Vwma.Tests.cs rename to lib/volume/vwma/tests/Vwma.Tests.cs diff --git a/lib/volume/vwma/Vwma.Validation.Tests.cs b/lib/volume/vwma/tests/Vwma.Validation.Tests.cs similarity index 100% rename from lib/volume/vwma/Vwma.Validation.Tests.cs rename to lib/volume/vwma/tests/Vwma.Validation.Tests.cs diff --git a/lib/volume/wad/Wad.Quantower.Tests.cs b/lib/volume/wad/tests/Wad.Quantower.Tests.cs similarity index 100% rename from lib/volume/wad/Wad.Quantower.Tests.cs rename to lib/volume/wad/tests/Wad.Quantower.Tests.cs diff --git a/lib/volume/wad/Wad.Tests.cs b/lib/volume/wad/tests/Wad.Tests.cs similarity index 100% rename from lib/volume/wad/Wad.Tests.cs rename to lib/volume/wad/tests/Wad.Tests.cs diff --git a/lib/volume/wad/Wad.Validation.Tests.cs b/lib/volume/wad/tests/Wad.Validation.Tests.cs similarity index 100% rename from lib/volume/wad/Wad.Validation.Tests.cs rename to lib/volume/wad/tests/Wad.Validation.Tests.cs