├── .gitignore ├── CryptoScanBot.Core ├── Account │ ├── AccountData.cs │ ├── AccountQuoteData.cs │ ├── AccountSymbolData.cs │ └── AccountSymbolIntervalData.cs ├── Barometer │ ├── BarometerData.cs │ ├── BarometerHelper.cs │ ├── BarometerPrice.cs │ ├── BarometerTools.cs │ └── BarometerVolume.cs ├── Const │ └── Constants.cs ├── Context │ ├── DataStore.cs │ ├── Database.cs │ ├── DateTimeHandler.cs │ ├── DateTimeOffsetHandler.cs │ ├── GuidHandler.cs │ ├── Migration.cs │ ├── SqliteTypeHandler.cs │ └── TimeSpanHandler.cs ├── Core │ ├── ApplicationParams.cs │ ├── CandleHelpers.cs │ ├── CandleTools.cs │ ├── Exception.cs │ ├── GlobalData.cs │ ├── IntervalTools.cs │ ├── PauseBarometer.cs │ ├── PauseTradingRule.cs │ ├── PositionMonitor.cs │ ├── PositionTools.cs │ ├── ScannerLog.cs │ ├── ScannerSession.cs │ ├── SymbolTools.cs │ ├── ThreadCheckFinishedPosition.cs │ ├── ThreadLoadData.cs │ ├── ThreadMonitorCandle.cs │ ├── ThreadMonitorOrder.cs │ └── ThreadSaveObjects.cs ├── CryptoScanBot.Core.csproj ├── Emulator │ ├── Emulator.cs │ ├── LoadHistoricalData.cs │ └── StorageHistoricalData.cs ├── Enums │ ├── CryptoAccountType.cs │ ├── CryptoApplicationStatus.cs │ ├── CryptoEntryOrDcaPricing.cs │ ├── CryptoEntryOrDcaStrategy.cs │ ├── CryptoExchangeType.cs │ ├── CryptoExternalUrlType.cs │ ├── CryptoIntervalPeriod.cs │ ├── CryptoOrderSide.cs │ ├── CryptoOrderStatus.cs │ ├── CryptoOrderType.cs │ ├── CryptoPartPurpose.cs │ ├── CryptoPositionStatus.cs │ ├── CryptoSignalStrategy.cs │ ├── CryptoTakeProfitStrategy.cs │ ├── CryptoTradeSide.cs │ ├── CryptoTradingApp.cs │ ├── CryptoTradingType.cs │ ├── CryptoTrailing.cs │ └── CryptoTrendIndicator.cs ├── Excel │ ├── BackTestExcel.cs │ ├── ExcelBase.cs │ ├── ExcelExchangeDump.cs │ ├── ExcelExtensions.cs │ ├── ExcelPositionDump.cs │ ├── ExcelPostionsDump.cs │ ├── ExcelSignalDump.cs │ ├── ExcelSignalsDump.cs │ └── ExcelSymbolDump.cs ├── Exchange │ ├── Altrady │ │ ├── Altrady - Position increase.json │ │ ├── Altrady - Position open.json │ │ ├── Altrady - Position set tp.json │ │ ├── Altrady - position cancel.json │ │ └── AltradyWebhook.cs │ ├── AssetBase.cs │ ├── Binance │ │ ├── Futures │ │ │ ├── Api.cs │ │ │ ├── Asset.cs │ │ │ ├── Candle.cs │ │ │ ├── Interval.cs │ │ │ ├── LimitRate.cs │ │ │ ├── Order.cs │ │ │ ├── SubscriptionKLineTicker.cs │ │ │ ├── SubscriptionPriceTicker.cs │ │ │ ├── SubscriptionUserTicker.cs │ │ │ ├── Symbol.cs │ │ │ └── Trade.cs │ │ └── Spot │ │ │ ├── Api.cs │ │ │ ├── Asset.cs │ │ │ ├── Candle.cs │ │ │ ├── FetchTradesForOrder.cs │ │ │ ├── Interval.cs │ │ │ ├── LimitRate.cs │ │ │ ├── Order.cs │ │ │ ├── SubscriptionKLineTicker.cs │ │ │ ├── SubscriptionPriceTicker.cs │ │ │ ├── SubscriptionUserTicker.cs │ │ │ ├── Symbol.cs │ │ │ └── Trade.cs │ ├── BybitApi │ │ ├── Futures │ │ │ ├── Api.cs │ │ │ ├── Asset.cs │ │ │ ├── Candle.cs │ │ │ ├── FetchTradesForOrder.cs │ │ │ ├── Interval.cs │ │ │ ├── LimitRate.cs │ │ │ ├── Order.cs │ │ │ ├── SubscriptionKLineTicker.cs │ │ │ ├── SubscriptionPriceTicker.cs │ │ │ ├── SubscriptionUserTicker.cs │ │ │ ├── Symbol.cs │ │ │ └── Trade.cs │ │ └── Spot │ │ │ ├── Api.cs │ │ │ ├── Asset.cs │ │ │ ├── Candle.cs │ │ │ ├── FetchTradesForOrder.cs │ │ │ ├── Interval.cs │ │ │ ├── LimitRate.cs │ │ │ ├── Order.cs │ │ │ ├── SubscriptionKLineTicker.cs │ │ │ ├── SubscriptionPriceTicker.cs │ │ │ ├── SubscriptionUserTicker.cs │ │ │ ├── Symbol.cs │ │ │ ├── Trade.cs │ │ │ └── json │ │ │ ├── buy - limit order.txt │ │ │ └── buy - stop limit order.txt │ ├── CandleBase.cs │ ├── ExchangeBase.cs │ ├── ExchangeHelper.cs │ ├── ExchangeOptions.cs │ ├── Kraken │ │ └── Spot │ │ │ ├── Api.cs │ │ │ ├── Asset.cs │ │ │ ├── Candle.cs │ │ │ ├── FetchTradesForOrder.cs │ │ │ ├── Interval.cs │ │ │ ├── LimitRate.cs │ │ │ ├── Order.cs │ │ │ ├── SubscriptionKLineTicker.cs │ │ │ ├── SubscriptionPriceTicker.cs │ │ │ ├── SubscriptionUserTicker.cs │ │ │ ├── Symbol.cs │ │ │ └── Trade.cs │ ├── Kucoin │ │ ├── Futures │ │ │ ├── Api.cs │ │ │ ├── Candles.cs │ │ │ ├── FetchTradesForOrder.cs │ │ │ ├── Interval.cs │ │ │ ├── KucoinWeights.cs │ │ │ ├── SubscriptionKLineTicker.cs │ │ │ ├── SubscriptionPriceTicker.cs │ │ │ ├── SubscriptionUserTicker.cs │ │ │ └── Symbol.cs │ │ └── Spot │ │ │ ├── Api.cs │ │ │ ├── Asset.cs │ │ │ ├── Candle.cs │ │ │ ├── Interval.cs │ │ │ ├── KucoinWeights.cs │ │ │ ├── Order.cs │ │ │ ├── SubscriptionKLineTicker.cs │ │ │ ├── SubscriptionPriceTicker.cs │ │ │ ├── SubscriptionUserTicker.cs │ │ │ ├── Symbol.cs │ │ │ └── Trade.cs │ ├── LimitRatesBase.cs │ ├── Mexc │ │ └── Spot │ │ │ ├── Api.cs │ │ │ ├── Asset.cs │ │ │ ├── Candle.cs │ │ │ ├── Interval.cs │ │ │ ├── LimitRate.cs │ │ │ ├── Order.cs │ │ │ ├── SubscriptionKLineTicker.cs │ │ │ ├── SubscriptionPriceTicker.cs │ │ │ ├── Symbol.cs │ │ │ ├── Trade.cs │ │ │ └── json │ │ │ ├── Candles.json │ │ │ └── Symbols.json │ ├── OrderBase.cs │ ├── SubscriptionTicker.cs │ ├── SymbolBase.cs │ ├── Ticker.cs │ ├── TickerGroup.cs │ ├── TradeBase.cs │ └── TradeParams.cs ├── Json │ ├── ColorConverter.cs │ ├── JsonTools.cs │ ├── RectangleConverter.cs │ └── SecureStringConverter.cs ├── Model │ ├── CryptoAccount.cs │ ├── CryptoAsset.cs │ ├── CryptoBalance.cs │ ├── CryptoCandle.cs │ ├── CryptoData.cs │ ├── CryptoExchange.cs │ ├── CryptoInterval.cs │ ├── CryptoLiveData.cs │ ├── CryptoOrder.cs │ ├── CryptoOrderList.cs │ ├── CryptoPosition.cs │ ├── CryptoPositionPart.cs │ ├── CryptoPositionStep.cs │ ├── CryptoQuoteData.cs │ ├── CryptoSequence.cs │ ├── CryptoSignal.cs │ ├── CryptoSymbol.cs │ ├── CryptoSymbolInterval.cs │ ├── CryptoTrade.cs │ ├── CryptoTradeList.cs │ ├── CryptoVersion.cs │ └── CryptoZone.cs ├── Settings │ ├── SettingsAltradyApi.cs │ ├── SettingsBackTest.cs │ ├── SettingsBalanceBot.cs │ ├── SettingsBasic.cs │ ├── SettingsCompiled.cs │ ├── SettingsExchangeApi.cs │ ├── SettingsGeneral.cs │ ├── SettingsLinks.cs │ ├── SettingsLinksAltrady.jpg │ ├── SettingsSignal.cs │ ├── SettingsTelegram.cs │ ├── SettingsTextual.cs │ ├── SettingsTrading.cs │ ├── SettingsUser.cs │ └── Strategy │ │ ├── SettingsSignalStrategyBase.cs │ │ ├── SettingsSignalStrategyFvg.cs │ │ ├── SettingsSignalStrategyJump.cs │ │ ├── SettingsSignalStrategySbm.cs │ │ ├── SettingsSignalStrategyStoRsi.cs │ │ ├── SettingsSignalStrategyStobb.cs │ │ └── SettingsSignalStrategyZones.cs ├── Signal │ ├── AlgorithmDefinition.cs │ ├── CandleIndicatorData.cs │ ├── Experiment │ │ ├── SignalBbRsiEngulfingLong.cs │ │ ├── SignalBbRsiEngulfingShort.cs │ │ ├── SignalSma50Sma20PriceLong.cs │ │ └── SignalSma50Sma20PriceShort.cs │ ├── LuxIndicator.cs │ ├── Momentum │ │ ├── SignalSbm1Long.cs │ │ ├── SignalSbm1Short.cs │ │ ├── SignalSbm2Long.cs │ │ ├── SignalSbm2Short.cs │ │ ├── SignalSbm3Long.cs │ │ ├── SignalSbm3Short.cs │ │ ├── SignalSbmBase.cs │ │ ├── SignalSbmBaseLong.cs │ │ ├── SignalSbmBaseShort.cs │ │ ├── SignalStoRsiLong.cs │ │ ├── SignalStoRsiMultiLong.cs │ │ ├── SignalStoRsiMultiShort.cs │ │ ├── SignalStoRsiShort.cs │ │ ├── SignalStobbLong.cs │ │ ├── SignalStobbMultiLong.cs │ │ ├── SignalStobbMultiShort.cs │ │ └── SignalStobbShort.cs │ ├── Other │ │ ├── SignalCandleJumpLong.cs │ │ ├── SignalCandleJumpShort.cs │ │ ├── SignalDominantLevelLong.cs │ │ ├── SignalDominantLevelShort.cs │ │ ├── SignalFairValueGapLong.cs │ │ ├── SignalFairValueGapShort.cs │ │ ├── SignalIchimokuKumoBreakoutLong.cs │ │ └── SignalIchimokuKumoBreakoutShort.cs │ ├── RegisterAlgorithms.cs │ ├── SignalBase.cs │ ├── SignalCreate.cs │ └── SignalHelper.cs ├── Sounds │ ├── Old │ │ ├── sound-jump-down.wav │ │ ├── sound-jump-up.wav │ │ ├── sound-sbm-overbought.wav │ │ ├── sound-sbm-oversold.wav │ │ ├── sound-stobb-overbought.wav │ │ ├── sound-stobb-oversold.wav │ │ ├── sound-storsi-overbought.wav │ │ └── sound-storsi-oversold.wav │ ├── Other │ │ ├── aksu.wav │ │ ├── ball_bearing.wav │ │ ├── bell_sound.wav │ │ ├── boing_sound_effect.wav │ │ ├── boxing_bell.wav │ │ ├── cool.wav │ │ ├── discord_halloween.wav │ │ ├── email_entact.wav │ │ ├── fade_in.wav │ │ ├── huawei.wav │ │ ├── la_cucaracha.wav │ │ ├── luana.wav │ │ ├── mind_transfer_no_jutsu.wav │ │ ├── notification.wav │ │ ├── popup.wav │ │ ├── proxima.wav │ │ ├── star_trek_energize.wav │ │ ├── suffocation.wav │ │ └── xiaomi_fress.wav │ ├── sound-domnear-overbought.wav │ ├── sound-domnear-oversold.wav │ ├── sound-domnearby-overbought.wav │ ├── sound-domnearby-oversold.wav │ ├── sound-heartbeat.wav │ ├── sound-jump-down.wav │ ├── sound-jump-up.wav │ ├── sound-sbm-overbought2.wav │ ├── sound-sbm-oversold2.wav │ ├── sound-stobb-overbought.wav │ ├── sound-stobb-overbought2.wav │ ├── sound-stobb-oversold.wav │ ├── sound-stobb-oversold2.wav │ ├── sound-storsi-overbought.wav │ ├── sound-storsi-oversold.wav │ ├── sound-trade-notification.wav │ ├── sound-trade-notification2.wav │ ├── sound-uuh-overbought.wav │ └── sound-uuh-oversold.wav ├── Telegram │ ├── TelegramCalculateZones.cs │ ├── TelegramResetScanner.cs │ ├── TelegramShowBarometer.cs │ ├── TelegramShowHelp.cs │ ├── TelegramShowStatus.cs │ ├── TelegramShowTrend.cs │ ├── TelegramShowValue.cs │ └── ThreadTelegramBot.cs ├── Trader │ ├── AssetTools.cs │ ├── PaperAssets.cs │ ├── PaperTrading.cs │ ├── TradeHandler.cs │ ├── TradeTools.cs │ ├── TradingConfig.cs │ └── TradingRules.cs ├── TradingView │ ├── FearAndGreatIndex.cs │ ├── TradingViewExtractor.cs │ ├── TradingViewJsonParser.cs │ └── TradingViewPoller.cs ├── Trend │ ├── MarketTrend.cs │ ├── TrendInterval.cs │ ├── TrendTools.cs │ ├── ZigZagIndicator10.cs │ ├── ZigZagIndicator11.cs │ ├── ZigZagIndicator14.cs │ ├── ZigZagIndicator9.cs │ ├── ZigZagLanceBeggs.cs │ └── ZigZagResult.cs └── Zones │ ├── CandleEngine.cs │ ├── CryptoZoneData.cs │ ├── CryptoZoneSession.cs │ ├── FairValueGap.cs │ ├── LiquidityZones.cs │ └── ThreadZoneCalculate.cs ├── CryptoScanBot.CoreTests ├── CryptoScanBot.CoreTests.csproj ├── Intern │ ├── CandleToolsTests.cs │ └── IntervalToolsTests.cs ├── TestBase.cs ├── Trader │ ├── PaperAssetsTests.cs │ └── TradeToolsTest.cs └── Trend │ ├── ETHUSDT │ ├── ETHUSDT-1h.json │ ├── Strange trend lines 1h.png │ └── ZigZagIndicator9TestsEth.cs │ └── STETHUSDT │ ├── STETHUSDT-1h.json │ ├── Strange trend lines 1h + indexes.png │ ├── Strange trend lines 1h.png │ └── ZigZagIndicator9TestsStet.cs ├── CryptoScanBot.ZoneVisualisation ├── ApplicationTools.cs ├── CryptoCharting.cs ├── CryptoScanBot.ZoneVisualisation.csproj ├── CryptoVisualisation.Designer.cs ├── CryptoVisualisation.cs ├── CryptoVisualisation.resx └── ExtraData.cs ├── CryptoScanBot.sln ├── CryptoScanBot ├── AboutBox.Designer.cs ├── AboutBox.cs ├── AboutBox.resx ├── AskSymbolDialog.Designer.cs ├── AskSymbolDialog.cs ├── AskSymbolDialog.resx ├── Commands │ ├── Command.cs │ ├── CommandAbout.cs │ ├── CommandCopyDataCells.cs │ ├── CommandCopySymbolInfo.cs │ ├── CommandHelper.cs │ ├── CommandShowGraph.cs │ ├── CommandShowTrendInfo.cs │ ├── CommandTools.cs │ ├── CommandTradingViewImportList.cs │ └── ToolStripMenuItemCommand.cs ├── CryptoDataGrid.cs ├── CryptoDataGridColumns.Designer.cs ├── CryptoDataGridColumns.cs ├── CryptoDataGridColumns.resx ├── CryptoDataGridLiveData.cs ├── CryptoDataGridPositionsClosed.cs ├── CryptoDataGridPositionsOpen.cs ├── CryptoDataGridSignal.cs ├── CryptoDataGridSymbol.cs ├── CryptoScanBot.csproj ├── Help │ ├── CryptoScanBot.docx │ ├── CryptoScanBot.pdf │ ├── Release Changes.txt │ ├── Roadmap.txt │ └── Weblinks example.json ├── Intern │ ├── LinkTools.cs │ ├── SoundPlayer.cs │ ├── SpeechPlayer.cs │ └── WebBrowser.cs ├── Main.Designer.cs ├── Main.cs ├── Main.resx ├── Program.cs ├── Properties │ ├── AssemblyInfo.cs │ ├── Resources.Designer.cs │ ├── Resources.resx │ ├── Settings.Designer.cs │ ├── Settings.settings │ ├── app.manifest │ └── launchSettings.json ├── Resource1.Designer.cs ├── Resource1.resx ├── Resources │ ├── ButtonOnOffGreen.png │ ├── ButtonOnOffRed.png │ ├── icons.ico │ ├── logoPictureBox.Image.jpg │ ├── open-folder.png │ ├── open-folder1.png │ ├── open-folderblack.png │ └── volume.png ├── SettingsDialog │ ├── SettingsDialog.Designer.cs │ ├── SettingsDialog.cs │ ├── SettingsDialog.resx │ ├── UserControlAltradyApi.Designer.cs │ ├── UserControlAltradyApi.cs │ ├── UserControlAltradyApi.resx │ ├── UserControlBarometer.Designer.cs │ ├── UserControlBarometer.cs │ ├── UserControlBarometer.resx │ ├── UserControlBarometerInterval.Designer.cs │ ├── UserControlBarometerInterval.cs │ ├── UserControlBarometerInterval.resx │ ├── UserControlColorAndSound.Designer.cs │ ├── UserControlColorAndSound.cs │ ├── UserControlColorAndSound.resx │ ├── UserControlEverything.Designer.cs │ ├── UserControlEverything.cs │ ├── UserControlEverything.resx │ ├── UserControlExchangeApi.Designer.cs │ ├── UserControlExchangeApi.cs │ ├── UserControlExchangeApi.resx │ ├── UserControlInterval.Designer.cs │ ├── UserControlInterval.cs │ ├── UserControlInterval.resx │ ├── UserControlMarketTrend.Designer.cs │ ├── UserControlMarketTrend.cs │ ├── UserControlMarketTrend.resx │ ├── UserControlMarketTrendRange.Designer.cs │ ├── UserControlMarketTrendRange.cs │ ├── UserControlMarketTrendRange.resx │ ├── UserControlQuote.Designer.cs │ ├── UserControlQuote.cs │ ├── UserControlQuote.resx │ ├── UserControlQuoteHeader.Designer.cs │ ├── UserControlQuoteHeader.cs │ ├── UserControlQuoteHeader.resx │ ├── UserControlSettingsPlaySoundAndColors.Designer.cs │ ├── UserControlSettingsPlaySoundAndColors.cs │ ├── UserControlSettingsPlaySoundAndColors.resx │ ├── UserControlStrategy.Designer.cs │ ├── UserControlStrategy.cs │ ├── UserControlStrategy.resx │ ├── UserControlTelegram.Designer.cs │ ├── UserControlTelegram.cs │ ├── UserControlTelegram.resx │ ├── UserControlTradeDca.Designer.cs │ ├── UserControlTradeDca.cs │ ├── UserControlTradeDca.resx │ ├── UserControlTradeDcaItem.Designer.cs │ ├── UserControlTradeDcaItem.cs │ ├── UserControlTradeDcaItem.resx │ ├── UserControlTradeEntry.Designer.cs │ ├── UserControlTradeEntry.cs │ ├── UserControlTradeEntry.resx │ ├── UserControlTradeRule.Designer.cs │ ├── UserControlTradeRule.cs │ ├── UserControlTradeRule.resx │ ├── UserControlTradeRuleItem.Designer.cs │ ├── UserControlTradeRuleItem.cs │ ├── UserControlTradeRuleItem.resx │ ├── UserControlTradeStopLoss.Designer.cs │ ├── UserControlTradeStopLoss.cs │ ├── UserControlTradeStopLoss.resx │ ├── UserControlTradeTakeProfit.Designer.cs │ ├── UserControlTradeTakeProfit.cs │ ├── UserControlTradeTakeProfit.resx │ ├── UserControlTrendInterval.Designer.cs │ ├── UserControlTrendInterval.cs │ └── UserControlTrendInterval.resx ├── UserControls │ ├── DashBoardControl.Designer.cs │ ├── DashBoardControl.cs │ ├── DashBoardControl.resx │ ├── DashBoardInformation.Designer.cs │ ├── DashBoardInformation.cs │ └── DashBoardInformation.resx ├── WinFormTools.cs └── app.config ├── CryptoScanner.png ├── CryptoShowTrend ├── CryptoShowTrend.csproj ├── Program.cs └── Properties │ └── launchSettings.json ├── ExchangeTest ├── EmulatorTest.cs ├── Exchange │ ├── Altrady │ │ └── AltradyWebhook.cs │ ├── Binance │ │ └── FileName.cs │ ├── Bybit │ │ ├── FileName.cs │ │ ├── Spot │ │ │ ├── Candles.cs │ │ │ ├── CandlesEmulator.cs │ │ │ └── Test.cs │ │ └── SpotUta │ │ │ ├── FileName.cs │ │ │ └── Test.cs │ └── Kucoin │ │ └── Futures │ │ ├── Candles.cs │ │ ├── SubscriptionKLineTicker.cs │ │ ├── SubscriptionPriceTicker.cs │ │ └── Symbols.cs ├── ExchangeTest.csproj ├── Form1.Designer.cs ├── Form1.cs ├── Form1.resx ├── Program.cs └── Properties │ └── launchSettings.json ├── README.md ├── Testjes ├── BackTest │ ├── BackTest.cs │ ├── BackTestConfig.cs │ ├── BackTestData.cs │ ├── BackTestEmulator.cs │ └── BackTestResults.cs ├── CryptoScanBotTestjes.csproj ├── Program.cs ├── Properties │ └── launchSettings.json ├── TestForm.Designer.cs ├── TestForm.cs └── TestForm.resx ├── Tradedash Sounds ├── 01_Tradedash - Notification.mp3 ├── 02_Tradedash - Notification.wav ├── 03_Tradedash - More alert.mp3 ├── 04_Tradedash - More alert.wav ├── 05_Tradedash - Less alert.wav └── 06_Tradedash - Less alert.mp3 ├── testEnvironments.json └── trading app urls.html /CryptoScanBot.Core/Account/AccountQuoteData.cs: -------------------------------------------------------------------------------- 1 | using CryptoScanBot.Core.Barometer; 2 | using CryptoScanBot.Core.Core; 3 | using CryptoScanBot.Core.Enums; 4 | 5 | namespace CryptoScanBot.Core.Account; 6 | 7 | public class AccountQuoteData 8 | { 9 | public required string QuoteName { get; set; } 10 | 11 | // The pausing values for each side 12 | public Dictionary PauseBarometerList { get; set; } = []; 13 | 14 | // The barometer values for each interval 15 | public Dictionary BarometerDataList { get; set; } = []; 16 | 17 | 18 | 19 | public AccountQuoteData() 20 | { 21 | // Initialize sides 22 | PauseBarometerList = new() 23 | { 24 | { CryptoTradeSide.Long, new PauseBarometer() }, 25 | { CryptoTradeSide.Short, new PauseBarometer() } 26 | }; 27 | 28 | // Initialize intervals 29 | for (CryptoIntervalPeriod interval = CryptoIntervalPeriod.interval1m; interval <= CryptoIntervalPeriod.interval1d; interval++) 30 | BarometerDataList[interval] = new BarometerData(); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /CryptoScanBot.Core/Account/AccountSymbolIntervalData.cs: -------------------------------------------------------------------------------- 1 | using CryptoScanBot.Core.Enums; 2 | using CryptoScanBot.Core.Model; 3 | 4 | namespace CryptoScanBot.Core.Account; 5 | 6 | public class AccountSymbolIntervalData 7 | { 8 | public required virtual CryptoInterval Interval { get; set; } 9 | public required CryptoIntervalPeriod IntervalPeriod { get; set; } 10 | 11 | // Trend: Last calculated trend & date 12 | public long? TrendInfoUnix { get; set; } 13 | public DateTime? TrendInfoDate { get; set; } 14 | public CryptoTrendIndicator TrendIndicator { get; set; } 15 | 16 | 17 | // Zones: Primary trend, recalculated if outside 18 | // Administration liquidity zones calculation?? How? 19 | public long? TimeLastSwingPoint { get; set; } 20 | public decimal? BestLongZone { get; internal set; } = 100m; // distance% 21 | public decimal? LastSwingHigh { get; internal set; } = null; 22 | 23 | public decimal? BestShortZone { get; internal set; } = 100m; // distance% 24 | public decimal? LastSwingLow { get; internal set; } = null; 25 | 26 | 27 | public void ResetZoneData() 28 | { 29 | LastSwingLow = null; 30 | LastSwingHigh = null; 31 | TimeLastSwingPoint = null; 32 | } 33 | 34 | public void ResetTrendData() 35 | { 36 | TrendInfoUnix = null; 37 | TrendInfoDate = null; 38 | TrendIndicator = CryptoTrendIndicator.Sideways; 39 | } 40 | } -------------------------------------------------------------------------------- /CryptoScanBot.Core/Barometer/BarometerData.cs: -------------------------------------------------------------------------------- 1 | namespace CryptoScanBot.Core.Barometer; 2 | 3 | /// The last calculated price or volume barometer values 4 | public class BarometerData 5 | { 6 | public long? PriceDateTime { get; set; } = null; 7 | public decimal? PriceBarometer { get; set; } = null; 8 | 9 | // Experimental, needs another attemp in the future! 10 | public long? VolumeDateTime { get; set; } = null; 11 | public decimal? VolumeBarometer { get; set; } = null; 12 | 13 | 14 | public void Clear() 15 | { 16 | PriceDateTime = null; 17 | PriceBarometer = null; 18 | 19 | VolumeDateTime = null; 20 | VolumeBarometer = null; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /CryptoScanBot.Core/Barometer/BarometerHelper.cs: -------------------------------------------------------------------------------- 1 | using CryptoScanBot.Core.Core; 2 | using CryptoScanBot.Core.Enums; 3 | using CryptoScanBot.Core.Model; 4 | 5 | namespace CryptoScanBot.Core.Barometer; 6 | 7 | public static class BarometerHelper 8 | { 9 | 10 | public static bool CheckValidBarometer(CryptoAccount account, string quoteName, CryptoIntervalPeriod intervalPeriod, (decimal minValue, decimal maxValue) values, out string reaction) 11 | { 12 | if (!GlobalData.IntervalListPeriod.TryGetValue(intervalPeriod, out CryptoInterval? interval)) 13 | { 14 | reaction = $"Interval {intervalPeriod} does not exist"; // impossible but voila 15 | return false; 16 | } 17 | 18 | // We gaan ervan uit dat alles in 1x wordt berekend 19 | BarometerData? barometerData = account.Data.GetBarometer(quoteName, intervalPeriod); 20 | if (!barometerData.PriceBarometer.HasValue) 21 | { 22 | reaction = $"Barometer {interval.Name} not calculated"; 23 | return false; 24 | } 25 | 26 | if (!barometerData.PriceBarometer.IsBetween(values.minValue, values.maxValue)) 27 | { 28 | string minValueStr = values.minValue.ToString0("N2"); 29 | if (values.minValue == decimal.MinValue) 30 | minValueStr = "-maxint"; 31 | string maxValueStr = values.maxValue.ToString0("N2"); 32 | if (values.maxValue == decimal.MaxValue) 33 | maxValueStr = "+maxint"; 34 | reaction = $"Barometer {interval.Name} {barometerData.PriceBarometer?.ToString0("N2")} not between {minValueStr} and {maxValueStr}"; 35 | return false; 36 | } 37 | 38 | 39 | reaction = ""; 40 | return true; 41 | } 42 | 43 | 44 | public static bool ValidBarometerConditions(CryptoAccount account, string quoteName, Dictionary barometer, out string reaction) 45 | { 46 | foreach (KeyValuePair item in barometer) 47 | { 48 | if (!CheckValidBarometer(account, quoteName, item.Key, item.Value, out reaction)) 49 | return false; 50 | } 51 | 52 | reaction = ""; 53 | return true; 54 | } 55 | 56 | } 57 | -------------------------------------------------------------------------------- /CryptoScanBot.Core/Barometer/BarometerPrice.cs: -------------------------------------------------------------------------------- 1 | using CryptoScanBot.Core.Model; 2 | 3 | namespace CryptoScanBot.Core.Barometer; 4 | 5 | internal class BarometerPrice 6 | { 7 | public static bool CalculatePriceBarometer(CryptoQuoteData quoteData, SortedList symbols, CryptoInterval interval, long unixCandleLast, out decimal barometerPerc) 8 | { 9 | // Wat is de candle in het vorige interval 10 | long unixCandlePrev = unixCandleLast - interval.Duration; 11 | 12 | // debug 13 | //DateTime dateCandlePrev = CandleTools.GetUnixDate(unixCandlePrev); 14 | //DateTime dateCandleLast = CandleTools.GetUnixDate(unixCandleLast); 15 | 16 | decimal sumPerc = 0; 17 | int coinsMatching = 0; 18 | 19 | for (int i = 0; i < quoteData.SymbolList.Count; i++) // foreach with ToList() is overkill 20 | { 21 | CryptoSymbol symbol = quoteData.SymbolList[i]; 22 | CryptoSymbolInterval symbolInterval = symbol.GetSymbolInterval(Enums.CryptoIntervalPeriod.interval1m); 23 | if (symbolInterval.CandleList.TryGetValue(unixCandlePrev, out CryptoCandle? candlePrev) && symbolInterval.CandleList.TryGetValue(unixCandleLast, out CryptoCandle? candleLast)) 24 | { 25 | if (candlePrev != null && candleLast != null) // Er worden in kucoin null candles toegevoegd? 26 | { 27 | decimal perc; 28 | decimal diff = candleLast.Close - candlePrev.Close; 29 | if (!candlePrev.Close.Equals(0)) 30 | perc = 100m * (diff / candlePrev.Close); 31 | else perc = 0; 32 | 33 | sumPerc += perc; 34 | coinsMatching++; 35 | } 36 | } 37 | } 38 | 39 | if (coinsMatching > 0) 40 | { 41 | decimal result = sumPerc / coinsMatching; 42 | barometerPerc = decimal.Round(result, 8); 43 | } 44 | else 45 | barometerPerc = 0m; // not -99 because of long/short. 46 | 47 | return coinsMatching > 0; // Met 1 munt krijgen we okay, mhhhh geeft een aardig vertekend beeld in dat geval.. 48 | } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /CryptoScanBot.Core/Const/Constants.cs: -------------------------------------------------------------------------------- 1 | namespace CryptoScanBot.Core.Const; 2 | 3 | public static class Constants 4 | { 5 | public const int BarometerGraphHours = 7; 6 | 7 | public const string SymbolNameBarometerPrice = "$BMP"; // Price barometer 8 | //public const string SymbolNameBarometerVolume = "$BMV"; // Volume barometer an experiment, needs to be continued someday 9 | } -------------------------------------------------------------------------------- /CryptoScanBot.Core/Context/DateTimeHandler.cs: -------------------------------------------------------------------------------- 1 | using Dapper; 2 | 3 | using System.Data; 4 | 5 | namespace CryptoScanBot.Core.Context; 6 | 7 | // Dapper slaat de kind van een datum niet op waardoor de UTC van slag is 8 | 9 | // from https://stackoverflow.com/questions/12510299/get-datetime-as-utc-with-dapper 10 | 11 | public class DateTimeHandler : SqlMapper.TypeHandler 12 | { 13 | private static readonly DateTime unixOrigin = new(1970, 1, 1, 0, 0, 0, 0); 14 | 15 | 16 | public override void SetValue(IDbDataParameter parameter, DateTime value) 17 | { 18 | parameter.Value = value; 19 | } 20 | 21 | //public override DateTime Parse(object value) 22 | //{ 23 | // return DateTime.SpecifyKind((DateTime)value, DateTimeKind.Utc); 24 | //} 25 | 26 | public override DateTime Parse(object value) 27 | { 28 | if (!TryGetDateTime(value, out DateTime storedDateValue)) 29 | { 30 | throw new InvalidOperationException($"Unable to parse value {value} as DateTimeOffset"); 31 | } 32 | 33 | return DateTime.SpecifyKind(storedDateValue, DateTimeKind.Utc); 34 | } 35 | 36 | private static bool TryGetDateTime(object value, out DateTime dateTimeValue) 37 | { 38 | dateTimeValue = default; 39 | if (value is DateTime d) 40 | { 41 | dateTimeValue = d; 42 | return true; 43 | } 44 | 45 | if (value is string v) 46 | { 47 | dateTimeValue = DateTime.Parse(v); 48 | return true; 49 | } 50 | 51 | if (long.TryParse(value?.ToString() ?? string.Empty, out long l)) 52 | { 53 | dateTimeValue = unixOrigin.AddSeconds(l); 54 | return true; 55 | } 56 | 57 | if (float.TryParse(value?.ToString() ?? string.Empty, out float _)) 58 | { 59 | throw new InvalidOperationException("Unsupported Sqlite datetime type, REAL."); 60 | } 61 | 62 | return false; 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /CryptoScanBot.Core/Context/DateTimeOffsetHandler.cs: -------------------------------------------------------------------------------- 1 | namespace CryptoScanBot.Core.Context; 2 | 3 | class DateTimeOffsetHandler : SqliteTypeHandler 4 | { 5 | public override DateTimeOffset Parse(object value) => DateTimeOffset.Parse((string)value); 6 | } 7 | -------------------------------------------------------------------------------- /CryptoScanBot.Core/Context/GuidHandler.cs: -------------------------------------------------------------------------------- 1 | namespace CryptoScanBot.Core.Context; 2 | 3 | class GuidHandler : SqliteTypeHandler 4 | { 5 | public override Guid Parse(object value) => Guid.Parse((string)value); 6 | } 7 | -------------------------------------------------------------------------------- /CryptoScanBot.Core/Context/SqliteTypeHandler.cs: -------------------------------------------------------------------------------- 1 | using Dapper; 2 | 3 | using System.Data; 4 | 5 | namespace CryptoScanBot.Core.Context; 6 | 7 | // From https://learn.microsoft.com/en-us/dotnet/standard/data/sqlite/dapper-limitations 8 | 9 | abstract class SqliteTypeHandler : SqlMapper.TypeHandler 10 | { 11 | // Parameters are converted by Microsoft.Data.Sqlite 12 | public override void SetValue(IDbDataParameter parameter, T? value) => parameter.Value = value; 13 | } 14 | -------------------------------------------------------------------------------- /CryptoScanBot.Core/Context/TimeSpanHandler.cs: -------------------------------------------------------------------------------- 1 | namespace CryptoScanBot.Core.Context; 2 | 3 | class TimeSpanHandler : SqliteTypeHandler 4 | { 5 | public override TimeSpan Parse(object value) => TimeSpan.Parse((string)value); 6 | } 7 | -------------------------------------------------------------------------------- /CryptoScanBot.Core/Core/ApplicationParams.cs: -------------------------------------------------------------------------------- 1 | using CommandLine; 2 | 3 | namespace CryptoScanBot.Core.Core; 4 | 5 | // Define a class to receive parsed values 6 | public class ApplicationParams 7 | { 8 | 9 | public string? _AppDataFolder; 10 | [Option('f', "folder", Required = false, HelpText = "De te gebruiken folder in de APPDATA")] 11 | public string? AppDataFolder { get { return _AppDataFolder; } set { _AppDataFolder = value!.Trim(); } } 12 | 13 | // Een idee? Dan hoeven we niet zo raar te switchen (soms midden in het ophalen van candles ) 14 | private string? _ExchangeName; 15 | [Option('e', "exchange", Required = false, HelpText = "De te gebruiken exchange (Binance Spot, Binance Futures, Bybit Spot, ByBit Futures, Kucoin Spot of Mexc Spot)")] 16 | public string? ExchangeName { get { return _ExchangeName; } set { _ExchangeName = value!.Trim(); } } 17 | 18 | public static ApplicationParams? Options { get; set; } 19 | 20 | public static void InitApplicationOptions() 21 | { 22 | if (Options == null) 23 | { 24 | string[] args = Environment.GetCommandLineArgs(); 25 | Options = Parser.Default.ParseArguments(args).Value; 26 | } 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /CryptoScanBot.Core/Core/Exception.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.Serialization; 2 | 3 | namespace CryptoScanBot.Core.Core; 4 | 5 | public class ExchangeException(string message) : SystemException(message), ISerializable 6 | { 7 | } 8 | -------------------------------------------------------------------------------- /CryptoScanBot.Core/Core/PauseBarometer.cs: -------------------------------------------------------------------------------- 1 | namespace CryptoScanBot.Core.Core; 2 | 3 | /// Data of pause trading if barometer is out of boundaries 4 | public class PauseBarometer 5 | { 6 | public DateTime? Calculated { get; set; } 7 | public DateTime? Until { get; set; } 8 | public string? Text { get; set; } 9 | } 10 | -------------------------------------------------------------------------------- /CryptoScanBot.Core/Core/PauseTradingRule.cs: -------------------------------------------------------------------------------- 1 | namespace CryptoScanBot.Core.Core; 2 | 3 | /// Data of pause trading rulez or barometer if the price drops 4 | public class PauseTradingRule 5 | { 6 | public DateTime? Calculated { get; set; } 7 | public DateTime? Until { get; set; } 8 | public string? Text { get; set; } 9 | 10 | 11 | public void Clear() 12 | { 13 | Calculated = null; 14 | Until = null; 15 | Text = ""; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /CryptoScanBot.Core/Core/ThreadMonitorCandle.cs: -------------------------------------------------------------------------------- 1 | using CryptoScanBot.Core.Enums; 2 | using CryptoScanBot.Core.Model; 3 | 4 | using System.Collections.Concurrent; 5 | 6 | namespace CryptoScanBot.Core.Core; 7 | 8 | public class ThreadMonitorCandle 9 | { 10 | private readonly SemaphoreSlim Semaphore = new(4); // X threads tegelijk 11 | private readonly BlockingCollection<(CryptoSymbol symbol, CryptoCandle candle)> Queue = []; 12 | private readonly CancellationTokenSource cancellationToken = new(); 13 | 14 | 15 | public void Stop() 16 | { 17 | cancellationToken.Cancel(); 18 | //GlobalData.AddTextToLogTab(string.Format("Stop monitor candle")); 19 | } 20 | 21 | 22 | public void AddToQueue(CryptoSymbol symbol, CryptoCandle candle) 23 | { 24 | if (!GlobalData.BackTest && GlobalData.ApplicationStatus == CryptoApplicationStatus.Running) 25 | Queue.Add((symbol, candle)); 26 | } 27 | 28 | 29 | public void Execute() 30 | { 31 | //GlobalData.AddTextToLogTab("Starting task for creating signals"); 32 | try 33 | { 34 | foreach ((CryptoSymbol symbol, CryptoCandle candle) in Queue.GetConsumingEnumerable(cancellationToken.Token)) 35 | { 36 | Task.Run(async () => 37 | { 38 | await Semaphore.WaitAsync(); 39 | try 40 | { 41 | // Er is een 1m candle gearriveerd, acties adhv deze candle.. 42 | PositionMonitor positionMonitor = new(GlobalData.ActiveAccount!, symbol, candle); 43 | await positionMonitor.NewCandleArrivedAsync(); 44 | } 45 | finally 46 | { 47 | Semaphore.Release(); 48 | } 49 | } 50 | ).ConfigureAwait(false); 51 | } 52 | } 53 | catch (OperationCanceledException) 54 | { 55 | // niets.. 56 | } 57 | catch (Exception error) 58 | { 59 | ScannerLog.Logger.Error(error, ""); 60 | GlobalData.AddTextToLogTab($"ThreadMonitorCandle ERROR {error.Message}"); 61 | } 62 | 63 | GlobalData.AddTextToLogTab("ThreadMonitorCandle candle thread exit"); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /CryptoScanBot.Core/Core/ThreadMonitorOrder.cs: -------------------------------------------------------------------------------- 1 | using CryptoScanBot.Core.Enums; 2 | using CryptoScanBot.Core.Model; 3 | using CryptoScanBot.Core.Trader; 4 | 5 | using System.Collections.Concurrent; 6 | 7 | namespace CryptoScanBot.Core.Core; 8 | 9 | public class ThreadMonitorOrder 10 | { 11 | private readonly CancellationTokenSource cancellationToken = new(); 12 | private readonly BlockingCollection<(CryptoSymbol symbol, CryptoOrderStatus status, CryptoOrder order)> Queue = []; 13 | 14 | 15 | public void Stop() 16 | { 17 | cancellationToken.Cancel(); 18 | GlobalData.AddTextToLogTab("Stop order monitor"); 19 | } 20 | 21 | 22 | public void AddToQueue((CryptoSymbol symbol, CryptoOrderStatus orderStatus, CryptoOrder order) data) 23 | { 24 | Queue.Add(data); 25 | } 26 | 27 | 28 | public async Task ExecuteAsync() 29 | { 30 | GlobalData.AddTextToLogTab("Task order monitor started"); 31 | foreach ((CryptoSymbol symbol, CryptoOrderStatus orderStatus, CryptoOrder order) in Queue.GetConsumingEnumerable(cancellationToken.Token)) 32 | { 33 | try 34 | { 35 | await TradeHandler.HandleTradeAsync(symbol, orderStatus, order); 36 | } 37 | catch (Exception error) 38 | { 39 | ScannerLog.Logger.Error(error, ""); 40 | GlobalData.AddTextToLogTab($"{symbol.Name} ERROR order monitor thread {error.Message}"); 41 | } 42 | } 43 | GlobalData.AddTextToLogTab("Task order monitor stopped"); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /CryptoScanBot.Core/Enums/CryptoAccountType.cs: -------------------------------------------------------------------------------- 1 | namespace CryptoScanBot.Core.Enums; 2 | 3 | public enum CryptoAccountType 4 | { 5 | BackTest = 0, 6 | PaperTrade = 1, 7 | RealTrading = 2, 8 | Altrady = 3, 9 | } 10 | -------------------------------------------------------------------------------- /CryptoScanBot.Core/Enums/CryptoApplicationStatus.cs: -------------------------------------------------------------------------------- 1 | namespace CryptoScanBot.Core.Enums; 2 | 3 | public enum CryptoApplicationStatus 4 | { 5 | Initializing, 6 | Running 7 | } -------------------------------------------------------------------------------- /CryptoScanBot.Core/Enums/CryptoEntryOrDcaPricing.cs: -------------------------------------------------------------------------------- 1 | namespace CryptoScanBot.Core.Enums; 2 | 3 | public enum CryptoEntryOrDcaPricing 4 | { 5 | SignalPrice, 6 | MarketPrice, 7 | BidPrice, 8 | AskPrice 9 | } 10 | -------------------------------------------------------------------------------- /CryptoScanBot.Core/Enums/CryptoEntryOrDcaStrategy.cs: -------------------------------------------------------------------------------- 1 | namespace CryptoScanBot.Core.Enums; 2 | 3 | // for both entry or dca 4 | public enum CryptoEntryOrDcaStrategy 5 | { 6 | AfterNextSignal, // Stap op een melding in (rekening houdende met cooldown en percentage indien DCA) 7 | FixedPercentage, // Stap in op een gefixeerde percentage (rekening houdende met cooldown en percentage indien DCA) 8 | TrailViaKcPsar // Stap in na een signaal of fixed percentage en ga dan boven (of beneden) trailen 9 | } 10 | -------------------------------------------------------------------------------- /CryptoScanBot.Core/Enums/CryptoExchangeType.cs: -------------------------------------------------------------------------------- 1 | namespace CryptoScanBot.Core.Enums; 2 | 3 | public enum CryptoExchangeType 4 | { 5 | Binance = 1, 6 | Bybit = 2, 7 | Kraken = 3, 8 | Kucoin = 4, 9 | Mexc = 5, 10 | } -------------------------------------------------------------------------------- /CryptoScanBot.Core/Enums/CryptoExternalUrlType.cs: -------------------------------------------------------------------------------- 1 | namespace CryptoScanBot.Core.Enums; 2 | 3 | public enum CryptoExternalUrlType 4 | { 5 | Internal, 6 | External 7 | } -------------------------------------------------------------------------------- /CryptoScanBot.Core/Enums/CryptoIntervalPeriod.cs: -------------------------------------------------------------------------------- 1 | namespace CryptoScanBot.Core.Enums; 2 | 3 | // Timeframe 4 | public enum CryptoIntervalPeriod 5 | { 6 | interval1m, //0 7 | interval2m, //1 8 | interval3m, //2 9 | interval5m, //3 10 | interval10m, //4 11 | interval15m, //5 12 | interval30m, //6 13 | interval1h, //7 14 | interval2h, //8 15 | interval3h, //9 16 | interval4h, //10 17 | interval6h, //11 18 | interval8h, //12 19 | interval12h, //13 20 | interval1d //14 21 | } 22 | 23 | -------------------------------------------------------------------------------- /CryptoScanBot.Core/Enums/CryptoOrderSide.cs: -------------------------------------------------------------------------------- 1 | namespace CryptoScanBot.Core.Enums; 2 | 3 | public enum CryptoOrderSide 4 | { 5 | Buy, 6 | Sell 7 | } 8 | -------------------------------------------------------------------------------- /CryptoScanBot.Core/Enums/CryptoOrderStatus.cs: -------------------------------------------------------------------------------- 1 | namespace CryptoScanBot.Core.Enums; 2 | 3 | // De status van een order (c.q. step) 4 | public enum CryptoOrderStatus 5 | { 6 | New, 7 | PartiallyFilled, 8 | PartiallyAndClosed, 9 | Filled, 10 | // Alles hierna is een verklaring waarom de order geannuleerd is 11 | Canceled, 12 | Expired, 13 | Timeout, 14 | BarameterToLow, 15 | TradingRules, 16 | PositionClosed, 17 | ChangedSettings, 18 | ChangedBreakEven, 19 | JoJoSell, 20 | TrailingChange, 21 | ManuallyByUser 22 | } 23 | 24 | public static class OrderHelper 25 | { 26 | public static string ToText(this CryptoOrderStatus status) 27 | { 28 | // The text "PartiallyAndClosed" is actually filled with an additional an internal purpose 29 | if (status == CryptoOrderStatus.PartiallyAndClosed) 30 | return "Filled"; 31 | else 32 | return status.ToString(); 33 | } 34 | } 35 | 36 | -------------------------------------------------------------------------------- /CryptoScanBot.Core/Enums/CryptoOrderType.cs: -------------------------------------------------------------------------------- 1 | namespace CryptoScanBot.Core.Enums; 2 | 3 | // De ondersteunde types (alleen Binance heeft OCO) 4 | public enum CryptoOrderType 5 | { 6 | Market, // Het "beste" bod van de markt 7 | Limit, // Een standaard order 8 | StopLimit, // Een stoplimit order 9 | Oco // OCO's alleen op Binance 10 | } 11 | -------------------------------------------------------------------------------- /CryptoScanBot.Core/Enums/CryptoPartPurpose.cs: -------------------------------------------------------------------------------- 1 | namespace CryptoScanBot.Core.Enums; 2 | 3 | public enum CryptoPartPurpose 4 | { 5 | /// 6 | /// Initial entry 7 | /// 8 | Entry, 9 | /// 10 | /// Additional entries 11 | /// 12 | Dca, 13 | /// 14 | /// Take profit 15 | /// 16 | TakeProfit 17 | } 18 | -------------------------------------------------------------------------------- /CryptoScanBot.Core/Enums/CryptoPositionStatus.cs: -------------------------------------------------------------------------------- 1 | namespace CryptoScanBot.Core.Enums; 2 | 3 | public enum CryptoPositionStatus 4 | { 5 | Waiting, // 0 6 | Trading, // 1 7 | Ready, // 2 8 | Timeout, // 3 9 | TakeOver, // 4 10 | Altrady, // 5 11 | } 12 | -------------------------------------------------------------------------------- /CryptoScanBot.Core/Enums/CryptoSignalStrategy.cs: -------------------------------------------------------------------------------- 1 | namespace CryptoScanBot.Core.Enums; 2 | 3 | public enum CryptoSignalStrategy 4 | { 5 | Jump = 0, 6 | 7 | Sbm1 = 1, 8 | Sbm2 = 2, 9 | Sbm3 = 3, 10 | Stobb = 6, 11 | StobbMulti = 7, 12 | 13 | IchimokuKumoBreakout = 9, // nazoeken, in de juiste positieve of negatieve trend doet ie het prima 14 | 15 | StoRsi = 10, // WGHM - STOSCH en RSI momentum indicator 16 | StoRsiMulti = 11, // WGHM - STOSCH en RSI momentum indicator 17 | StoRsi2 = 12, // = STORSI, repeated storsi 18 | StoRsi3 = 13, // = STORSI, 2, but different 19 | 20 | BbRsiEngulfing = 50, 21 | SignalSma50Sma20Price = 52, 22 | 23 | DominantLevel = 1000, 24 | FairValueGap = 1001, 25 | } -------------------------------------------------------------------------------- /CryptoScanBot.Core/Enums/CryptoTakeProfitStrategy.cs: -------------------------------------------------------------------------------- 1 | namespace CryptoScanBot.Core.Enums; 2 | 3 | public enum CryptoTakeProfitStrategy 4 | { 5 | FixedPercentage, // Het opgegeven vaste percentage 6 | TrailViaKcPsar, // stop limit sell op de bovenste KC/PSAR 7 | //DynamicPercentage, // Het percentage adhv BB breedte 8 | } 9 | -------------------------------------------------------------------------------- /CryptoScanBot.Core/Enums/CryptoTradeSide.cs: -------------------------------------------------------------------------------- 1 | namespace CryptoScanBot.Core.Enums; 2 | 3 | public enum CryptoTradeSide 4 | { 5 | Long, 6 | Short 7 | } 8 | -------------------------------------------------------------------------------- /CryptoScanBot.Core/Enums/CryptoTradingApp.cs: -------------------------------------------------------------------------------- 1 | namespace CryptoScanBot.Core.Enums; 2 | 3 | public enum CryptoTradingApp 4 | { 5 | Altrady, 6 | Hypertrader, 7 | TradingView, 8 | ExchangeUrl, 9 | } 10 | -------------------------------------------------------------------------------- /CryptoScanBot.Core/Enums/CryptoTradingType.cs: -------------------------------------------------------------------------------- 1 | namespace CryptoScanBot.Core.Enums; 2 | 3 | public enum CryptoTradingType 4 | { 5 | Spot, 6 | Futures 7 | } -------------------------------------------------------------------------------- /CryptoScanBot.Core/Enums/CryptoTrailing.cs: -------------------------------------------------------------------------------- 1 | namespace CryptoScanBot.Core.Enums; 2 | 3 | public enum CryptoTrailing 4 | { 5 | None, 6 | Trailing 7 | //Reserved // gereserveerde DCA order 8 | } 9 | 10 | -------------------------------------------------------------------------------- /CryptoScanBot.Core/Enums/CryptoTrendIndicator.cs: -------------------------------------------------------------------------------- 1 | namespace CryptoScanBot.Core.Enums; 2 | 3 | public enum CryptoTrendIndicator 4 | { 5 | Sideways = 0, // of onbekend (nieuwe coin, te weinig candles) 6 | Bullish = 1, 7 | Bearish = 2 8 | } 9 | -------------------------------------------------------------------------------- /CryptoScanBot.Core/Excel/ExcelExtensions.cs: -------------------------------------------------------------------------------- 1 | using NPOI.SS.UserModel; 2 | 3 | namespace CryptoScanBot.Core.Excel; 4 | 5 | public static class ExcelExtensions 6 | { 7 | public static IRow GetOrCreateRow(this ISheet sheet, int rowIndex) => sheet.GetRow(rowIndex) ?? sheet.CreateRow(rowIndex); 8 | public static ICell GetOrCreateCell(this IRow sheet, int columnIndex) => sheet.GetCell(columnIndex) ?? sheet.CreateCell(columnIndex); 9 | public static ICell WithValue(this ICell cell, double? value) 10 | { 11 | if (value.HasValue) 12 | cell.SetCellValue(value.Value); 13 | return cell; 14 | } 15 | public static ICell WithValue(this ICell cell, string? value) 16 | { 17 | if (!string.IsNullOrEmpty(value)) 18 | cell.SetCellValue(value); 19 | return cell; 20 | } 21 | public static ICell WithValue(this ICell cell, DateTime? value) 22 | { 23 | if (value.HasValue) 24 | cell.SetCellValue(value.Value); 25 | return cell; 26 | } 27 | public static ICell WithStyle(this ICell cell, ICellStyle? style) 28 | { 29 | if (style != null) 30 | cell.CellStyle = style; 31 | return cell; 32 | } 33 | } -------------------------------------------------------------------------------- /CryptoScanBot.Core/Exchange/Altrady/Altrady - Position increase.json: -------------------------------------------------------------------------------- 1 | { 2 | "test": false, 3 | "api_key": "079a28d2-02ca-4678-8092-dddafc0d92b2", 4 | "api_secret": "71f6646f-b7c7-4d6d-83a6-7500a8be3a3f", 5 | 6 | "exchange": "BYBI", 7 | "symbol": "BYBI_USDT_NAKA", 8 | "signal_id": "testpositionidnaka_4", 9 | 10 | "action": "increase", 11 | "side": "long", 12 | "order_type": "limit", 13 | "adjust_fee": false, 14 | 15 | "increase_order": { 16 | "quantity_percentage": "200", 17 | "price": "1.110" 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /CryptoScanBot.Core/Exchange/Altrady/Altrady - Position open.json: -------------------------------------------------------------------------------- 1 | { 2 | "test": false, 3 | "api_key": "079a28d2-02ca-4678-8092-dddafc0d92b2", 4 | "api_secret": "71f6646f-b7c7-4d6d-83a6-7500a8be3a3f", 5 | 6 | "exchange": "BYBI", 7 | "symbol": "BYBI_USDT_NAKA", 8 | "signal_id": "testpositionidnaka_4", 9 | 10 | "action": "open", 11 | "side": "long", 12 | "order_type": "limit", 13 | "quote_amount": "25.00", 14 | "signal_price": 1.1400, 15 | "adjust_fee": false 16 | 17 | 18 | } 19 | -------------------------------------------------------------------------------- /CryptoScanBot.Core/Exchange/Altrady/Altrady - Position set tp.json: -------------------------------------------------------------------------------- 1 | { 2 | "test": false, 3 | "api_key": "079a28d2-02ca-4678-8092-dddafc0d92b2", 4 | "api_secret": "71f6646f-b7c7-4d6d-83a6-7500a8be3a3f", 5 | 6 | "exchange": "BYBI", 7 | "symbol": "BYBI_USDT_NAKA", 8 | "signal_id": "testpositionidnaka_4", 9 | 10 | "action": "open", 11 | "side": "long", 12 | "take_profit": [ 13 | { 14 | "price_percentage": 0.76, 15 | "position_percentage": 100 16 | } 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /CryptoScanBot.Core/Exchange/Altrady/Altrady - position cancel.json: -------------------------------------------------------------------------------- 1 | { 2 | "test": false, 3 | "api_key": "079a28d2-02ca-4678-8092-dddafc0d92b2", 4 | "api_secret": "71f6646f-b7c7-4d6d-83a6-7500a8be3a3f", 5 | 6 | "exchange": "BYBI", 7 | "symbol": "BYBI_USDT_NAKA", 8 | "signal_id": "testpositionidnaka_4", 9 | 10 | "action": "close", 11 | "side": "long", 12 | "order_type": "market", 13 | "_signal_price": 1.200 14 | } 15 | -------------------------------------------------------------------------------- /CryptoScanBot.Core/Exchange/AssetBase.cs: -------------------------------------------------------------------------------- 1 | namespace CryptoScanBot.Core.Exchange; 2 | 3 | public class AssetBase() 4 | { 5 | } 6 | -------------------------------------------------------------------------------- /CryptoScanBot.Core/Exchange/Binance/Futures/Interval.cs: -------------------------------------------------------------------------------- 1 | using Binance.Net.Enums; 2 | 3 | using CryptoScanBot.Core.Enums; 4 | 5 | namespace CryptoScanBot.Core.Exchange.Binance.Futures; 6 | 7 | public class Interval 8 | { 9 | public static KlineInterval? GetExchangeInterval(CryptoIntervalPeriod interval) 10 | { 11 | return interval switch 12 | { 13 | CryptoIntervalPeriod.interval1m => KlineInterval.OneMinute, 14 | CryptoIntervalPeriod.interval3m => KlineInterval.ThreeMinutes, 15 | CryptoIntervalPeriod.interval5m => KlineInterval.FiveMinutes, 16 | CryptoIntervalPeriod.interval15m => KlineInterval.FifteenMinutes, 17 | CryptoIntervalPeriod.interval30m => KlineInterval.ThirtyMinutes, 18 | CryptoIntervalPeriod.interval1h => KlineInterval.OneHour, 19 | CryptoIntervalPeriod.interval2h => KlineInterval.TwoHour, 20 | CryptoIntervalPeriod.interval4h => KlineInterval.FourHour, 21 | CryptoIntervalPeriod.interval6h => KlineInterval.SixHour, 22 | CryptoIntervalPeriod.interval8h => KlineInterval.EightHour, 23 | CryptoIntervalPeriod.interval12h => KlineInterval.TwelveHour, 24 | CryptoIntervalPeriod.interval1d => KlineInterval.OneDay, 25 | _ => null, 26 | }; 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /CryptoScanBot.Core/Exchange/Binance/Futures/SubscriptionKLineTicker.cs: -------------------------------------------------------------------------------- 1 | using Binance.Net.Clients; 2 | using Binance.Net.Enums; 3 | using Binance.Net.Objects.Models.Spot.Socket; 4 | 5 | using CryptoExchange.Net.Objects; 6 | using CryptoExchange.Net.Objects.Sockets; 7 | 8 | using CryptoScanBot.Core.Core; 9 | using CryptoScanBot.Core.Model; 10 | 11 | namespace CryptoScanBot.Core.Exchange.Binance.Futures; 12 | 13 | public class SubscriptionKLineTicker(ExchangeOptions exchangeOptions) : SubscriptionTicker(exchangeOptions) 14 | { 15 | private async Task ProcessCandleAsync(BinanceStreamKlineData kline) 16 | { 17 | if (GlobalData.ExchangeListName.TryGetValue(ExchangeBase.ExchangeOptions.ExchangeName, out Model.CryptoExchange? exchange)) 18 | { 19 | if (exchange.SymbolListName.TryGetValue(kline.Symbol, out CryptoSymbol? symbol)) 20 | { 21 | Interlocked.Increment(ref TickerCount); 22 | //GlobalData.AddTextToLogTab(String.Format("{0} Candle {1} start processing", temp.Symbol, temp.Data.OpenTime.ToLocalTime())); 23 | //string json = JsonSerializer.Serialize(kline, ExchangeHelper.JsonSerializerNotIndented); 24 | //ScannerLog.Logger.Trace($"kline ticker {symbol.Name} {json}"); 25 | var candle = await CandleTools.Process1mCandleAsync(symbol, kline.Data.OpenTime, kline.Data.OpenPrice, kline.Data.HighPrice, kline.Data.LowPrice, kline.Data.ClosePrice, kline.Data.Volume, kline.Data.QuoteVolume); 26 | GlobalData.ThreadMonitorCandle!.AddToQueue(symbol, candle); 27 | } 28 | } 29 | } 30 | 31 | 32 | public override async Task?> Subscribe() 33 | { 34 | TickerGroup!.SocketClient ??= new BinanceSocketClient(); 35 | CallResult subscriptionResult = await ((BinanceSocketClient)TickerGroup.SocketClient).UsdFuturesApi.ExchangeData.SubscribeToKlineUpdatesAsync( 36 | Symbols, KlineInterval.OneMinute, (data) => 37 | { 38 | if (data.Data.Data.Final) 39 | { 40 | Task.Run(async () => { await ProcessCandleAsync((BinanceStreamKlineData)data.Data); }); 41 | } 42 | }, ExchangeBase.CancellationToken).ConfigureAwait(false); 43 | return subscriptionResult; 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /CryptoScanBot.Core/Exchange/Binance/Futures/SubscriptionPriceTicker.cs: -------------------------------------------------------------------------------- 1 | using Binance.Net.Clients; 2 | using Binance.Net.Objects.Models.Spot.Socket; 3 | 4 | using CryptoExchange.Net.Objects; 5 | using CryptoExchange.Net.Objects.Sockets; 6 | 7 | using CryptoScanBot.Core.Core; 8 | using CryptoScanBot.Core.Model; 9 | 10 | namespace CryptoScanBot.Core.Exchange.Binance.Futures; 11 | 12 | public class SubscriptionPriceTicker(ExchangeOptions exchangeOptions) : SubscriptionTicker(exchangeOptions) 13 | { 14 | public override async Task?> Subscribe() 15 | { 16 | TickerGroup!.SocketClient ??= new BinanceSocketClient(); 17 | CallResult subscriptionResult = await ((BinanceSocketClient)TickerGroup.SocketClient).UsdFuturesApi.ExchangeData.SubscribeToAllTickerUpdatesAsync((data) => 18 | { 19 | if (GlobalData.ExchangeListName.TryGetValue(ExchangeBase.ExchangeOptions.ExchangeName, out Model.CryptoExchange? exchange)) 20 | { 21 | //GET /api/v3/ticker/24hr 22 | // client.Spot.SubscribeToSymbolTickerUpdates("ETHBTC", (test) => result = test); 23 | 24 | foreach (var tick in data.Data.Cast()) 25 | { 26 | if (exchange.SymbolListName.TryGetValue(tick.Symbol, out CryptoSymbol? symbol)) 27 | { 28 | Interlocked.Increment(ref TickerCount); 29 | 30 | if (!GlobalData.BackTest) 31 | { 32 | symbol.LastPrice = tick.LastPrice; 33 | symbol.BidPrice = tick.BestBidPrice; 34 | symbol.AskPrice = tick.BestAskPrice; 35 | symbol.Volume = tick.QuoteVolume; //= Quoted = het volume * de prijs 36 | } 37 | } 38 | } 39 | 40 | if (TickerCount > 999999999) 41 | Interlocked.Exchange(ref TickerCount, 0); 42 | } 43 | }, ExchangeBase.CancellationToken).ConfigureAwait(false); 44 | 45 | return subscriptionResult; 46 | } 47 | 48 | } 49 | -------------------------------------------------------------------------------- /CryptoScanBot.Core/Exchange/Binance/Spot/Interval.cs: -------------------------------------------------------------------------------- 1 | using Binance.Net.Enums; 2 | 3 | using CryptoScanBot.Core.Enums; 4 | 5 | namespace CryptoScanBot.Core.Exchange.Binance.Spot; 6 | 7 | public class Interval 8 | { 9 | public static KlineInterval? GetExchangeInterval(CryptoIntervalPeriod interval) 10 | { 11 | return interval switch 12 | { 13 | CryptoIntervalPeriod.interval1m => KlineInterval.OneMinute, 14 | CryptoIntervalPeriod.interval3m => KlineInterval.ThreeMinutes, 15 | CryptoIntervalPeriod.interval5m => KlineInterval.FiveMinutes, 16 | CryptoIntervalPeriod.interval15m => KlineInterval.FifteenMinutes, 17 | CryptoIntervalPeriod.interval30m => KlineInterval.ThirtyMinutes, 18 | CryptoIntervalPeriod.interval1h => KlineInterval.OneHour, 19 | CryptoIntervalPeriod.interval2h => KlineInterval.TwoHour, 20 | CryptoIntervalPeriod.interval4h => KlineInterval.FourHour, 21 | CryptoIntervalPeriod.interval6h => KlineInterval.SixHour, 22 | CryptoIntervalPeriod.interval8h => KlineInterval.EightHour, 23 | CryptoIntervalPeriod.interval12h => KlineInterval.TwelveHour, 24 | CryptoIntervalPeriod.interval1d => KlineInterval.OneDay, 25 | _ => null, 26 | }; 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /CryptoScanBot.Core/Exchange/Binance/Spot/SubscriptionPriceTicker.cs: -------------------------------------------------------------------------------- 1 | using Binance.Net.Clients; 2 | using Binance.Net.Objects.Models.Spot.Socket; 3 | 4 | using CryptoExchange.Net.Objects; 5 | using CryptoExchange.Net.Objects.Sockets; 6 | 7 | using CryptoScanBot.Core.Core; 8 | using CryptoScanBot.Core.Model; 9 | 10 | namespace CryptoScanBot.Core.Exchange.Binance.Spot; 11 | 12 | public class SubscriptionPriceTicker(ExchangeOptions exchangeOptions) : SubscriptionTicker(exchangeOptions) 13 | { 14 | public override async Task?> Subscribe() 15 | { 16 | TickerGroup!.SocketClient ??= new BinanceSocketClient(); 17 | CallResult subscriptionResult = await ((BinanceSocketClient)TickerGroup.SocketClient).SpotApi.ExchangeData.SubscribeToAllTickerUpdatesAsync((data) => 18 | { 19 | if (GlobalData.ExchangeListName.TryGetValue(ExchangeBase.ExchangeOptions.ExchangeName, out Model.CryptoExchange? exchange)) 20 | { 21 | //GET /api/v3/ticker/24hr 22 | // client.Spot.SubscribeToSymbolTickerUpdates("ETHBTC", (test) => result = test); 23 | 24 | foreach (BinanceStreamTick tick in data.Data.Cast()) 25 | { 26 | if (exchange.SymbolListName.TryGetValue(tick.Symbol, out CryptoSymbol? symbol)) 27 | { 28 | Interlocked.Increment(ref TickerCount); 29 | 30 | if (!GlobalData.BackTest) 31 | { 32 | symbol.LastPrice = tick.LastPrice; 33 | symbol.BidPrice = tick.BestBidPrice; 34 | symbol.AskPrice = tick.BestAskPrice; 35 | symbol.Volume = tick.QuoteVolume; //= Quoted = het volume * de prijs 36 | } 37 | } 38 | } 39 | 40 | if (TickerCount > 999999999) 41 | Interlocked.Exchange(ref TickerCount, 0); 42 | } 43 | }, ExchangeBase.CancellationToken).ConfigureAwait(false); 44 | 45 | return subscriptionResult; 46 | } 47 | 48 | } -------------------------------------------------------------------------------- /CryptoScanBot.Core/Exchange/BybitApi/Futures/Interval.cs: -------------------------------------------------------------------------------- 1 | using Bybit.Net.Enums; 2 | 3 | using CryptoScanBot.Core.Enums; 4 | 5 | namespace CryptoScanBot.Core.Exchange.BybitApi.Futures; 6 | 7 | public class Interval 8 | { 9 | public static KlineInterval? GetExchangeInterval(CryptoIntervalPeriod interval) 10 | { 11 | return interval switch 12 | { 13 | CryptoIntervalPeriod.interval1m => KlineInterval.OneMinute, 14 | CryptoIntervalPeriod.interval3m => KlineInterval.ThreeMinutes, 15 | CryptoIntervalPeriod.interval5m => KlineInterval.FiveMinutes, 16 | CryptoIntervalPeriod.interval15m => KlineInterval.FifteenMinutes, 17 | CryptoIntervalPeriod.interval30m => KlineInterval.ThirtyMinutes, 18 | CryptoIntervalPeriod.interval1h => KlineInterval.OneHour, 19 | CryptoIntervalPeriod.interval2h => KlineInterval.TwoHours, 20 | CryptoIntervalPeriod.interval4h => KlineInterval.FourHours, 21 | CryptoIntervalPeriod.interval6h => KlineInterval.SixHours, 22 | CryptoIntervalPeriod.interval12h => KlineInterval.TwelveHours, 23 | CryptoIntervalPeriod.interval1d => KlineInterval.OneDay, 24 | _ => null, 25 | }; 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /CryptoScanBot.Core/Exchange/BybitApi/Spot/Interval.cs: -------------------------------------------------------------------------------- 1 | using Bybit.Net.Enums; 2 | 3 | using CryptoScanBot.Core.Enums; 4 | 5 | namespace CryptoScanBot.Core.Exchange.BybitApi.Spot; 6 | 7 | public class Interval 8 | { 9 | public static KlineInterval? GetExchangeInterval(CryptoIntervalPeriod interval) 10 | { 11 | return interval switch 12 | { 13 | CryptoIntervalPeriod.interval1m => KlineInterval.OneMinute, 14 | CryptoIntervalPeriod.interval3m => KlineInterval.ThreeMinutes, 15 | CryptoIntervalPeriod.interval5m => KlineInterval.FiveMinutes, 16 | CryptoIntervalPeriod.interval15m => KlineInterval.FifteenMinutes, 17 | CryptoIntervalPeriod.interval30m => KlineInterval.ThirtyMinutes, 18 | CryptoIntervalPeriod.interval1h => KlineInterval.OneHour, 19 | CryptoIntervalPeriod.interval2h => KlineInterval.TwoHours, 20 | CryptoIntervalPeriod.interval4h => KlineInterval.FourHours, 21 | CryptoIntervalPeriod.interval6h => KlineInterval.SixHours, 22 | CryptoIntervalPeriod.interval12h => KlineInterval.TwelveHours, 23 | CryptoIntervalPeriod.interval1d => KlineInterval.OneDay, 24 | _ => null, 25 | }; 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /CryptoScanBot.Core/Exchange/BybitApi/Spot/json/buy - limit order.txt: -------------------------------------------------------------------------------- 1 | A 10 dollar limit order 2 | 3 | 2024-06-16 12:48:46.0083|DEBUG|CryptoScanBot.Core.Core.ScannerLog|APRSUSDT UserTicker Buy New order=1709589298862654464 quantity=17.25 price=0.5797 value=0.000000 4 | 5 | json={ 6 | "Category": 2, 7 | "OrderId": "1709589298862654464", 8 | "ClientOrderId": "1709589298862654465", 9 | "BlockTradeId": "", 10 | "Symbol": "APRSUSDT", 11 | "Price": 0.5797, 12 | "Quantity": 17.25, 13 | "Side": 0, 14 | "IsLeverage": false, 15 | "PositionIdx": 0, 16 | "Status": 1, 17 | "CancelType": 19, 18 | "RejectReason": "", 19 | "AveragePrice": null, 20 | "QuantityRemaining": null, 21 | "ValueRemaining": null, 22 | "QuantityFilled": 0.00, 23 | "ValueFilled": 0.000000, 24 | "ExecutedFee": 0, 25 | "FeeAsset": "", 26 | "TimeInForce": 0, 27 | "OrderType": 0, 28 | "StopOrderType": null, 29 | "OrderIv": null, 30 | "TriggerPrice": null, 31 | "TakeProfit": null, 32 | "StopLoss": null, 33 | "TakeProfitTriggerBy": null, 34 | "StopLossTriggerBy": null, 35 | "TriggerDirection": 0, 36 | "TriggerBy": null, 37 | "LastPriceOnCreated": null, 38 | "CloseOnTrigger": false, 39 | "ReduceOnly": false, 40 | "CreateTime": "2024-06-16T10:48:45.742Z", 41 | "UpdateTime": "2024-06-16T10:48:45.744Z", 42 | "CreateType": null, 43 | "MarketUnit": null, 44 | "OcoTriggerType": null, 45 | "TakeProfitLimitPrice": null, 46 | "StopLossLimitPrice": null, 47 | "SelfMatchPreventionType": 0, 48 | "SelfMatchPreventionGroup": 0, 49 | "SelfMatchPreventionOrderId": "", 50 | "TpSlMode": null, 51 | "PlaceType": null 52 | } -------------------------------------------------------------------------------- /CryptoScanBot.Core/Exchange/BybitApi/Spot/json/buy - stop limit order.txt: -------------------------------------------------------------------------------- 1 | 2024-06-16 12:51:12.5787|DEBUG|CryptoScanBot.Core.Core.ScannerLog|APRSUSDT UserTicker Buy Untriggered order=1709590529731494912 quantity=14.64 price=0.6830 value=0.000000 2 | 3 | json={ 4 | "Category": 2, 5 | "OrderId": "1709590529731494912", 6 | "ClientOrderId": "1709590529731494913", 7 | "BlockTradeId": "", 8 | "Symbol": "APRSUSDT", 9 | "Price": 0.6830, 10 | "Quantity": 14.64, 11 | "Side": 0, 12 | "IsLeverage": false, 13 | "PositionIdx": 0, 14 | "Status": 7, 15 | "CancelType": 19, 16 | "RejectReason": "", 17 | "AveragePrice": null, 18 | "QuantityRemaining": null, 19 | "ValueRemaining": null, 20 | "QuantityFilled": 0.00, 21 | "ValueFilled": null, 22 | "ExecutedFee": 0, 23 | "FeeAsset": "", 24 | "TimeInForce": 0, 25 | "OrderType": 0, 26 | "StopOrderType": 6, 27 | "OrderIv": null, 28 | "TriggerPrice": 0.6709, 29 | "TakeProfit": null, 30 | "StopLoss": null, 31 | "TakeProfitTriggerBy": null, 32 | "StopLossTriggerBy": null, 33 | "TriggerDirection": 0, 34 | "TriggerBy": null, 35 | "LastPriceOnCreated": null, 36 | "CloseOnTrigger": false, 37 | "ReduceOnly": false, 38 | "CreateTime": "2024-06-16T10:51:12.472Z", 39 | "UpdateTime": "2024-06-16T10:51:12.472Z", 40 | "CreateType": null, 41 | "MarketUnit": null, 42 | "OcoTriggerType": null, 43 | "TakeProfitLimitPrice": null, 44 | "StopLossLimitPrice": null, 45 | "SelfMatchPreventionType": 0, 46 | "SelfMatchPreventionGroup": 0, 47 | "SelfMatchPreventionOrderId": "", 48 | "TpSlMode": null, 49 | "PlaceType": null 50 | } 51 | -------------------------------------------------------------------------------- /CryptoScanBot.Core/Exchange/ExchangeOptions.cs: -------------------------------------------------------------------------------- 1 | namespace CryptoScanBot.Core.Exchange; 2 | 3 | public class ExchangeOptions 4 | { 5 | // Official exchange name (registered in database) 6 | public required string ExchangeName { get; set; } = ""; 7 | 8 | // Aantal symbols per subscription (een limiet van de exchange) 9 | public int SymbolLimitPerSubscription { get; set; } 10 | 11 | // Aantal subscriptions per client (een keuze in de techniek) 12 | public int SubscriptionLimitPerClient { get; set; } = 10; 13 | 14 | // Reduceer het aantal symbols adhv het volume (indien mogelijk) 15 | // - Specificly build for Kucoin because of the amount of symbols 16 | // - Skip symbol if specified volume if to low (quotedata volume limit) 17 | public bool LimitAmountOfSymbols { get; set; } 18 | 19 | // Limit for fetching candles 20 | public int CandleLimit { get; set; } = 1000; 21 | } 22 | -------------------------------------------------------------------------------- /CryptoScanBot.Core/Exchange/Kraken/Spot/Interval.cs: -------------------------------------------------------------------------------- 1 | using CryptoScanBot.Core.Enums; 2 | 3 | using Kraken.Net.Enums; 4 | 5 | namespace CryptoScanBot.Core.Exchange.Kraken.Spot; 6 | 7 | public class Interval 8 | { 9 | public static KlineInterval? GetExchangeInterval(CryptoIntervalPeriod interval) 10 | { 11 | return interval switch 12 | { 13 | CryptoIntervalPeriod.interval1m => KlineInterval.OneMinute, 14 | CryptoIntervalPeriod.interval5m => KlineInterval.FiveMinutes, 15 | CryptoIntervalPeriod.interval15m => KlineInterval.FifteenMinutes, 16 | CryptoIntervalPeriod.interval30m => KlineInterval.ThirtyMinutes, 17 | CryptoIntervalPeriod.interval1h => KlineInterval.OneHour, 18 | CryptoIntervalPeriod.interval4h => KlineInterval.FourHour, 19 | CryptoIntervalPeriod.interval1d => KlineInterval.OneDay, 20 | _ => null, 21 | }; 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /CryptoScanBot.Core/Exchange/Kraken/Spot/SubscriptionKLineTicker.cs: -------------------------------------------------------------------------------- 1 | using CryptoExchange.Net.Objects; 2 | using CryptoExchange.Net.Objects.Sockets; 3 | 4 | using CryptoScanBot.Core.Core; 5 | using CryptoScanBot.Core.Model; 6 | 7 | using Kraken.Net.Clients; 8 | using Kraken.Net.Enums; 9 | using Kraken.Net.Objects.Models.Socket; 10 | 11 | namespace CryptoScanBot.Core.Exchange.Kraken.Spot; 12 | 13 | public class SubscriptionKLineTicker(ExchangeOptions exchangeOptions) : SubscriptionTicker(exchangeOptions) 14 | { 15 | private async Task ProcessCandleAsync(string topic, KrakenKlineUpdate kline) 16 | { 17 | // De interval wordt geprefixed in de topic 18 | string symbolName = topic.Replace("/", ""); 19 | if (GlobalData.ExchangeListName.TryGetValue(ExchangeBase.ExchangeOptions.ExchangeName, out Model.CryptoExchange? exchange)) 20 | { 21 | if (exchange.SymbolListName.TryGetValue(symbolName, out CryptoSymbol? symbol)) 22 | { 23 | Interlocked.Increment(ref TickerCount); 24 | //GlobalData.AddTextToLogTab(String.Format("{0} Candle {1} start processing", topic, kline.Timestamp.ToLocalTime())); 25 | var candle = await CandleTools.Process1mCandleAsync(symbol, kline.OpenTime, kline.OpenPrice, kline.HighPrice, kline.LowPrice, kline.ClosePrice, 0, kline.Volume); 26 | GlobalData.ThreadMonitorCandle!.AddToQueue(symbol, candle); 27 | } 28 | } 29 | } 30 | 31 | public override async Task?> Subscribe() 32 | { 33 | List symbolList = []; 34 | foreach (var symbol in SymbolList) 35 | { 36 | symbolList.Add(symbol.Base + "/" + symbol.Quote); 37 | } 38 | 39 | TickerGroup!.SocketClient ??= new KrakenSocketClient(); 40 | var subscriptionResult = await ((KrakenSocketClient)TickerGroup.SocketClient).SpotApi.SubscribeToKlineUpdatesAsync( 41 | symbolList, KlineInterval.OneMinute, data => 42 | { 43 | foreach (KrakenKlineUpdate kline in data.Data) 44 | { 45 | Task.Run(async () => { await ProcessCandleAsync(data.Symbol ?? "", kline); }); 46 | } 47 | }, ExchangeBase.CancellationToken).ConfigureAwait(false); 48 | 49 | return subscriptionResult; 50 | } 51 | 52 | } 53 | -------------------------------------------------------------------------------- /CryptoScanBot.Core/Exchange/Kraken/Spot/SubscriptionPriceTicker.cs: -------------------------------------------------------------------------------- 1 | using CryptoExchange.Net.Objects; 2 | using CryptoExchange.Net.Objects.Sockets; 3 | 4 | using CryptoScanBot.Core.Core; 5 | using CryptoScanBot.Core.Model; 6 | 7 | using Kraken.Net.Clients; 8 | 9 | namespace CryptoScanBot.Core.Exchange.Kraken.Spot; 10 | 11 | public class SubscriptionPriceTicker(ExchangeOptions exchangeOptions) : SubscriptionTicker(exchangeOptions) 12 | { 13 | public override async Task?> Subscribe() 14 | { 15 | List symbolList = []; 16 | foreach (var symbol in SymbolList) 17 | { 18 | symbolList.Add(symbol.Base + "/" + symbol.Quote); 19 | } 20 | 21 | TickerGroup!.SocketClient ??= new KrakenSocketClient(); 22 | CallResult subscriptionResult = await ((KrakenSocketClient)TickerGroup.SocketClient).SpotApi.SubscribeToTickerUpdatesAsync(symbolList, data => 23 | { 24 | if (GlobalData.ExchangeListName.TryGetValue(ExchangeBase.ExchangeOptions.ExchangeName, out Model.CryptoExchange? exchange)) 25 | { 26 | var tick = data.Data; 27 | { 28 | string symbolName = data.Symbol?.Replace("/", "") ?? ""; 29 | if (exchange.SymbolListName.TryGetValue(symbolName, out CryptoSymbol? symbol)) 30 | { 31 | Interlocked.Increment(ref TickerCount); 32 | 33 | if (!GlobalData.BackTest) 34 | { 35 | symbol.LastPrice = tick.LastPrice; 36 | symbol.BidPrice = tick.BestBidPrice; 37 | symbol.AskPrice = tick.BestAskPrice; 38 | symbol.Volume = tick.Volume; 39 | } 40 | } 41 | } 42 | 43 | if (TickerCount > 999999999) 44 | Interlocked.Exchange(ref TickerCount, 0); 45 | } 46 | }, ExchangeBase.CancellationToken).ConfigureAwait(false); 47 | 48 | return subscriptionResult; 49 | } 50 | 51 | } -------------------------------------------------------------------------------- /CryptoScanBot.Core/Exchange/Kucoin/Futures/Interval.cs: -------------------------------------------------------------------------------- 1 | using CryptoScanBot.Core.Enums; 2 | using CryptoScanBot.Core.Model; 3 | 4 | using Kucoin.Net.Enums; 5 | 6 | namespace CryptoScanBot.Core.Exchange.Kucoin.Futures; 7 | 8 | public class Interval 9 | { 10 | public static FuturesKlineInterval? GetExchangeInterval(CryptoInterval interval) 11 | { 12 | return interval.IntervalPeriod switch 13 | { 14 | CryptoIntervalPeriod.interval1m => FuturesKlineInterval.OneMinute, 15 | //CryptoIntervalPeriod.interval3m => FuturesKlineInterval.ThreeMinutes, 16 | CryptoIntervalPeriod.interval5m => FuturesKlineInterval.FiveMinutes, 17 | CryptoIntervalPeriod.interval15m => FuturesKlineInterval.FifteenMinutes, 18 | CryptoIntervalPeriod.interval30m => FuturesKlineInterval.ThirtyMinutes, 19 | CryptoIntervalPeriod.interval1h => FuturesKlineInterval.OneHour, 20 | CryptoIntervalPeriod.interval2h => FuturesKlineInterval.TwoHours, 21 | CryptoIntervalPeriod.interval4h => FuturesKlineInterval.FourHours, 22 | //CryptoIntervalPeriod.interval6h => FuturesKlineInterval.SixHours, 23 | CryptoIntervalPeriod.interval8h => FuturesKlineInterval.EightHours, 24 | CryptoIntervalPeriod.interval12h => FuturesKlineInterval.TwelveHours, 25 | CryptoIntervalPeriod.interval1d => FuturesKlineInterval.OneDay, 26 | _ => null, 27 | }; 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /CryptoScanBot.Core/Exchange/Kucoin/Futures/SubscriptionUserTicker.cs: -------------------------------------------------------------------------------- 1 | using CryptoExchange.Net.Objects; 2 | using CryptoExchange.Net.Objects.Sockets; 3 | using Kucoin.Net.Clients; 4 | using Kucoin.Net.Objects.Models.Futures.Socket; 5 | 6 | namespace CryptoScanBot.Core.Exchange.Kucoin.Futures; 7 | 8 | #if TRADEBOT 9 | public class SubscriptionUserTicker(ExchangeOptions exchangeOptions) : SubscriptionTicker(exchangeOptions) 10 | { 11 | public override async Task?> Subscribe() 12 | { 13 | TickerGroup!.SocketClient ??= new KucoinSocketClient(); 14 | //var subscriptionResult = await ((KucoinSocketClient)TickerGroup.SocketClient).FuturesApi.SubscribeToTradeUpdatesAsync( OrderUpdatesAsync(OnOrderUpdate).ConfigureAwait(false); 15 | return null; // subscriptionResult; 16 | } 17 | 18 | private void OnOrderUpdate(DataEvent @event) 19 | { 20 | throw new NotImplementedException(); 21 | } 22 | } 23 | 24 | #endif 25 | -------------------------------------------------------------------------------- /CryptoScanBot.Core/Exchange/Kucoin/Spot/Asset.cs: -------------------------------------------------------------------------------- 1 | using CryptoScanBot.Core.Core; 2 | using CryptoScanBot.Core.Model; 3 | 4 | namespace CryptoScanBot.Core.Exchange.Kucoin.Spot; 5 | 6 | public class Asset() : AssetBase(), IAsset 7 | { 8 | public Task GetAssetsAsync(CryptoAccount tradeAccount) 9 | { 10 | //if (GlobalData.ExchangeListName.TryGetValue(ExchangeName, out Model.CryptoExchange? exchange)) 11 | { 12 | try 13 | { 14 | GlobalData.AddTextToLogTab($"Reading asset information from {ExchangeBase.ExchangeOptions.ExchangeName}"); 15 | 16 | //LimitRate.WaitForFairWeight(1); 17 | 18 | } 19 | catch (Exception error) 20 | { 21 | ScannerLog.Logger.Error(error, ""); 22 | GlobalData.AddTextToLogTab(error.ToString()); 23 | GlobalData.AddTextToLogTab(""); 24 | } 25 | 26 | } 27 | 28 | return Task.CompletedTask; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /CryptoScanBot.Core/Exchange/Kucoin/Spot/Interval.cs: -------------------------------------------------------------------------------- 1 | using CryptoScanBot.Core.Enums; 2 | 3 | using Kucoin.Net.Enums; 4 | 5 | namespace CryptoScanBot.Core.Exchange.Kucoin.Spot; 6 | 7 | public class Interval 8 | { 9 | public static KlineInterval? GetExchangeInterval(CryptoIntervalPeriod interval) 10 | { 11 | return interval switch 12 | { 13 | CryptoIntervalPeriod.interval1m => KlineInterval.OneMinute, 14 | CryptoIntervalPeriod.interval3m => KlineInterval.ThreeMinutes, 15 | CryptoIntervalPeriod.interval5m => KlineInterval.FiveMinutes, 16 | CryptoIntervalPeriod.interval15m => KlineInterval.FifteenMinutes, 17 | CryptoIntervalPeriod.interval30m => KlineInterval.ThirtyMinutes, 18 | CryptoIntervalPeriod.interval1h => KlineInterval.OneHour, 19 | CryptoIntervalPeriod.interval2h => KlineInterval.TwoHours, 20 | CryptoIntervalPeriod.interval4h => KlineInterval.FourHours, 21 | CryptoIntervalPeriod.interval6h => KlineInterval.SixHours, 22 | CryptoIntervalPeriod.interval8h => KlineInterval.EightHours, 23 | CryptoIntervalPeriod.interval12h => KlineInterval.TwelveHours, 24 | CryptoIntervalPeriod.interval1d => KlineInterval.OneDay, 25 | _ => null, 26 | }; 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /CryptoScanBot.Core/Exchange/Kucoin/Spot/Order.cs: -------------------------------------------------------------------------------- 1 | using CryptoScanBot.Core.Context; 2 | using CryptoScanBot.Core.Model; 3 | 4 | namespace CryptoScanBot.Core.Exchange.Kucoin.Spot; 5 | 6 | public class Order() : OrderBase(), IOrder 7 | { 8 | public Task GetOrdersAsync(CryptoDatabase database, CryptoPosition position) 9 | { 10 | return Task.FromResult(0); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /CryptoScanBot.Core/Exchange/Kucoin/Spot/SubscriptionUserTicker.cs: -------------------------------------------------------------------------------- 1 | using CryptoExchange.Net.Objects; 2 | using CryptoExchange.Net.Objects.Sockets; 3 | 4 | using Kucoin.Net.Clients; 5 | using Kucoin.Net.Objects.Models.Spot.Socket; 6 | 7 | namespace CryptoScanBot.Core.Exchange.Kucoin.Spot; 8 | 9 | public class SubscriptionUserTicker(ExchangeOptions exchangeOptions) : SubscriptionTicker(exchangeOptions) 10 | { 11 | public override async Task?> Subscribe() 12 | { 13 | TickerGroup!.SocketClient ??= new KucoinSocketClient(); 14 | var subscriptionResult = await ((KucoinSocketClient)TickerGroup.SocketClient).SpotApi.SubscribeToOrderUpdatesAsync(OnOrderUpdate).ConfigureAwait(false); 15 | return subscriptionResult; 16 | } 17 | 18 | private void OnOrderUpdate(DataEvent @event) 19 | { 20 | throw new NotImplementedException(); 21 | } 22 | } 23 | 24 | -------------------------------------------------------------------------------- /CryptoScanBot.Core/Exchange/Kucoin/Spot/Trade.cs: -------------------------------------------------------------------------------- 1 | using CryptoScanBot.Core.Context; 2 | using CryptoScanBot.Core.Model; 3 | 4 | namespace CryptoScanBot.Core.Exchange.Kucoin.Spot; 5 | 6 | public class Trade() : TradeBase(), ITrade 7 | { 8 | public Task GetTradesAsync(CryptoDatabase database, CryptoPosition position) 9 | { 10 | return Task.FromResult(0); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /CryptoScanBot.Core/Exchange/LimitRatesBase.cs: -------------------------------------------------------------------------------- 1 | namespace CryptoScanBot.Core.Exchange; 2 | 3 | public class LimitRatesBase() 4 | { 5 | } 6 | -------------------------------------------------------------------------------- /CryptoScanBot.Core/Exchange/Mexc/Spot/Asset.cs: -------------------------------------------------------------------------------- 1 | using CryptoScanBot.Core.Core; 2 | using CryptoScanBot.Core.Model; 3 | 4 | namespace CryptoScanBot.Core.Exchange.Mexc.Spot; 5 | 6 | public class Asset() : AssetBase(), IAsset 7 | { 8 | public Task GetAssetsAsync(CryptoAccount tradeAccount) 9 | { 10 | //if (GlobalData.ExchangeListName.TryGetValue(ExchangeName, out Model.CryptoExchange? exchange)) 11 | { 12 | try 13 | { 14 | GlobalData.AddTextToLogTab($"Reading asset information from {ExchangeBase.ExchangeOptions.ExchangeName}"); 15 | 16 | //LimitRate.WaitForFairWeight(1); 17 | 18 | } 19 | catch (Exception error) 20 | { 21 | ScannerLog.Logger.Error(error, ""); 22 | GlobalData.AddTextToLogTab(error.ToString()); 23 | GlobalData.AddTextToLogTab(""); 24 | } 25 | 26 | } 27 | 28 | return Task.CompletedTask; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /CryptoScanBot.Core/Exchange/Mexc/Spot/Interval.cs: -------------------------------------------------------------------------------- 1 | using CryptoScanBot.Core.Enums; 2 | 3 | using Mexc.Net.Enums; 4 | 5 | namespace CryptoScanBot.Core.Exchange.Mexc.Spot; 6 | 7 | public class Interval 8 | { 9 | public static KlineInterval? GetExchangeInterval(CryptoIntervalPeriod interval) 10 | { 11 | return interval switch 12 | { 13 | CryptoIntervalPeriod.interval1m => KlineInterval.OneMinute, 14 | CryptoIntervalPeriod.interval5m => KlineInterval.FiveMinutes, 15 | CryptoIntervalPeriod.interval15m => KlineInterval.FifteenMinutes, 16 | CryptoIntervalPeriod.interval30m => KlineInterval.ThirtyMinutes, 17 | CryptoIntervalPeriod.interval1h => KlineInterval.OneHour, 18 | CryptoIntervalPeriod.interval4h => KlineInterval.FourHours, 19 | CryptoIntervalPeriod.interval1d => KlineInterval.OneDay, 20 | _ => null, 21 | }; 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /CryptoScanBot.Core/Exchange/Mexc/Spot/Order.cs: -------------------------------------------------------------------------------- 1 | using CryptoScanBot.Core.Context; 2 | using CryptoScanBot.Core.Model; 3 | 4 | namespace CryptoScanBot.Core.Exchange.Mexc.Spot; 5 | 6 | public class Order() : OrderBase(), IOrder 7 | { 8 | public Task GetOrdersAsync(CryptoDatabase database, CryptoPosition position) 9 | { 10 | return Task.FromResult(0); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /CryptoScanBot.Core/Exchange/Mexc/Spot/SubscriptionPriceTicker.cs: -------------------------------------------------------------------------------- 1 | using CryptoExchange.Net.Objects; 2 | using CryptoExchange.Net.Objects.Sockets; 3 | 4 | using CryptoScanBot.Core.Core; 5 | using CryptoScanBot.Core.Model; 6 | 7 | using Mexc.Net.Clients; 8 | 9 | namespace CryptoScanBot.Core.Exchange.Mexc.Spot; 10 | 11 | public class SubscriptionPriceTicker(ExchangeOptions exchangeOptions) : SubscriptionTicker(exchangeOptions) 12 | { 13 | public override async Task?> Subscribe() 14 | { 15 | // TODO: quick en dirty code hier, nog eens verbeteren 16 | // We verwachten (helaas) slechts 1 symbol per ticker 17 | List symbols = []; 18 | //string symbolName = ""; 19 | foreach (var symbol in SymbolList) 20 | { 21 | //if (symbolName == "") 22 | // symbolName = symbol.Name; 23 | //else 24 | // symbolName += "," + symbol.Name; 25 | symbols.Add(symbol.Name); 26 | } 27 | 28 | 29 | TickerGroup!.SocketClient ??= new MexcSocketClient(); 30 | CallResult subscriptionResult = await ((MexcSocketClient)TickerGroup.SocketClient).SpotApi.SubscribeToMiniTickerUpdatesAsync(symbols, data => 31 | { 32 | if (GlobalData.ExchangeListName.TryGetValue(ExchangeBase.ExchangeOptions.ExchangeName, out Model.CryptoExchange? exchange)) 33 | { 34 | var tick = data.Data; 35 | { 36 | if (data.Symbol != null && exchange.SymbolListName.TryGetValue(data.Symbol, out CryptoSymbol? symbol)) 37 | { 38 | Interlocked.Increment(ref TickerCount); 39 | 40 | if (!GlobalData.BackTest) 41 | { 42 | symbol.LastPrice = tick.LastPrice; 43 | symbol.Volume = tick.QuoteVolume; //= Base = het volume * de prijs 44 | } 45 | } 46 | } 47 | 48 | if (TickerCount > 999999999) 49 | Interlocked.Exchange(ref TickerCount, 0); 50 | } 51 | }, null, ExchangeBase.CancellationToken).ConfigureAwait(false); 52 | 53 | return subscriptionResult; 54 | } 55 | 56 | } 57 | -------------------------------------------------------------------------------- /CryptoScanBot.Core/Exchange/Mexc/Spot/Trade.cs: -------------------------------------------------------------------------------- 1 | using CryptoScanBot.Core.Context; 2 | using CryptoScanBot.Core.Model; 3 | 4 | namespace CryptoScanBot.Core.Exchange.Mexc.Spot; 5 | 6 | public class Trade() : TradeBase(), ITrade 7 | { 8 | public Task GetTradesAsync(CryptoDatabase database, CryptoPosition position) 9 | { 10 | return Task.FromResult(0); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /CryptoScanBot.Core/Exchange/OrderBase.cs: -------------------------------------------------------------------------------- 1 | namespace CryptoScanBot.Core.Exchange; 2 | 3 | public class OrderBase() 4 | { 5 | 6 | } 7 | -------------------------------------------------------------------------------- /CryptoScanBot.Core/Exchange/SymbolBase.cs: -------------------------------------------------------------------------------- 1 | namespace CryptoScanBot.Core.Exchange; 2 | 3 | public class SymbolBase() 4 | { 5 | 6 | } 7 | -------------------------------------------------------------------------------- /CryptoScanBot.Core/Exchange/TickerGroup.cs: -------------------------------------------------------------------------------- 1 | using CryptoExchange.Net.Clients; 2 | 3 | namespace CryptoScanBot.Core.Exchange; 4 | 5 | public class TickerGroup : IDisposable 6 | { 7 | // Iedere client bedient maximaal 10 subscriptions 8 | // Iedere subscription bedient een aantal symbols 9 | // dat is zo'n 1..200 en afhankelijk van de exchange.. 10 | public BaseSocketClient? SocketClient; // made public for ExchangeTest project 11 | public List TickerList { get; set; } = []; 12 | 13 | 14 | public void Dispose() 15 | { 16 | Dispose(true); 17 | GC.SuppressFinalize(this); 18 | } 19 | 20 | protected virtual void Dispose(bool disposing) 21 | { 22 | if (disposing) 23 | { 24 | if (SocketClient != null) 25 | { 26 | SocketClient.Dispose(); 27 | SocketClient = null; 28 | } 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /CryptoScanBot.Core/Exchange/TradeBase.cs: -------------------------------------------------------------------------------- 1 | namespace CryptoScanBot.Core.Exchange; 2 | 3 | public class TradeBase() 4 | { 5 | 6 | } 7 | -------------------------------------------------------------------------------- /CryptoScanBot.Core/Exchange/TradeParams.cs: -------------------------------------------------------------------------------- 1 | using CryptoExchange.Net.Objects; 2 | 3 | using CryptoScanBot.Core.Enums; 4 | 5 | using System.Net; 6 | 7 | namespace CryptoScanBot.Core.Exchange; 8 | 9 | public class TradeParams 10 | { 11 | public CryptoPartPurpose Purpose { get; set; } 12 | public CryptoOrderSide OrderSide { get; set; } 13 | public CryptoOrderType OrderType { get; set; } 14 | public string? OrderId { get; set; } 15 | public decimal Price { get; set; } 16 | public decimal Quantity { get; set; } 17 | public decimal QuoteQuantity { get; set; } 18 | public DateTime CreateTime { get; set; } 19 | 20 | // OCO of StopLimit gerelateerd 21 | public decimal? StopPrice { get; set; } 22 | public decimal? LimitPrice { get; set; } 23 | public string? Order2Id { get; set; } 24 | 25 | // if error 26 | public HttpStatusCode? ResponseStatusCode { get; set; } 27 | public Error? Error { get; internal set; } 28 | 29 | // Debug (full json) 30 | public string? DebugJson { get; set; } 31 | } 32 | -------------------------------------------------------------------------------- /CryptoScanBot.Core/Json/ColorConverter.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel; 2 | using System.Drawing; 3 | using System.Text.Json; 4 | using System.Text.Json.Serialization; 5 | 6 | namespace CryptoScanBot.Core.Json; 7 | 8 | public class ColorConverter : JsonConverter 9 | { 10 | public override Color Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) 11 | { 12 | if (reader.TokenType is JsonTokenType.String) 13 | { 14 | string? text = reader.GetString(); 15 | if (!string.IsNullOrEmpty(text)) 16 | { 17 | if (text.Contains(',')) 18 | { 19 | string[] values = text.Split(','); 20 | if (int.TryParse(values[0], out int r) && 21 | int.TryParse(values[1], out int g) && 22 | int.TryParse(values[2], out int b)) 23 | return Color.FromArgb(r, g, b); 24 | } 25 | return ColorTranslator.FromHtml(text); 26 | } 27 | } 28 | 29 | return JsonSerializer.Deserialize(ref reader, JsonTools.DeSerializerOptions); 30 | } 31 | 32 | public override void Write(Utf8JsonWriter writer, Color value, JsonSerializerOptions options) 33 | { 34 | string output; 35 | 36 | if (value == Color.Empty) 37 | { 38 | output = string.Empty; 39 | } 40 | else if (value.IsNamedColor) 41 | { 42 | output = value.Name; 43 | } 44 | else 45 | { 46 | TypeConverter intConverter = TypeDescriptor.GetConverter(typeof(int)); 47 | int nArg = 0; 48 | 49 | string[] args; 50 | if (value.A < 255) 51 | { 52 | args = new string[4]; 53 | args[nArg++] = intConverter.ConvertToString(value.A)!; 54 | } 55 | else 56 | { 57 | args = new string[3]; 58 | } 59 | 60 | args[nArg++] = intConverter.ConvertToString(value.R)!; 61 | args[nArg++] = intConverter.ConvertToString(value.G)!; 62 | args[nArg++] = intConverter.ConvertToString(value.B)!; 63 | 64 | output = string.Join(", ", args); 65 | } 66 | 67 | writer.WriteStringValue(output); 68 | } 69 | } -------------------------------------------------------------------------------- /CryptoScanBot.Core/Json/JsonTools.cs: -------------------------------------------------------------------------------- 1 | using System.Text.Encodings.Web; 2 | using System.Text.Json; 3 | 4 | namespace CryptoScanBot.Core.Json; 5 | 6 | public class JsonTools 7 | { 8 | public static readonly JsonSerializerOptions JsonSerializerIndented = new() 9 | { 10 | AllowTrailingCommas = true, 11 | Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping, 12 | IncludeFields = true, 13 | IgnoreReadOnlyFields = true, 14 | PropertyNameCaseInsensitive = true, 15 | WriteIndented = true, 16 | }; 17 | 18 | public static readonly JsonSerializerOptions JsonSerializerNotIndented = new() 19 | { 20 | AllowTrailingCommas = true, 21 | Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping, 22 | IncludeFields = true, 23 | IgnoreReadOnlyFields = true, 24 | PropertyNameCaseInsensitive = true, 25 | WriteIndented = false, 26 | }; 27 | 28 | public static readonly JsonSerializerOptions DeSerializerOptions = new() 29 | { 30 | AllowTrailingCommas = true, 31 | Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping, 32 | IncludeFields = true, 33 | IgnoreReadOnlyFields = true, 34 | PropertyNameCaseInsensitive = true, 35 | WriteIndented = true, 36 | }; 37 | } 38 | -------------------------------------------------------------------------------- /CryptoScanBot.Core/Json/RectangleConverter.cs: -------------------------------------------------------------------------------- 1 | using System.Buffers; 2 | using System.Drawing; 3 | using System.Text.Json; 4 | using System.Text.Json.Serialization; 5 | 6 | namespace CryptoScanBot.Core.Json; 7 | 8 | public class RectangleConverter : JsonConverter 9 | { 10 | public override Rectangle Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) 11 | { 12 | // Old Newtonsoft.Json value 13 | if (reader.TokenType is JsonTokenType.String) 14 | { 15 | int valueLength = reader.HasValueSequence ? (int)reader.ValueSequence.Length : reader.ValueSpan.Length; 16 | char[] buffer = ArrayPool.Shared.Rent(valueLength); 17 | int charsRead = reader.CopyString(buffer); 18 | ReadOnlySpan text = buffer.AsSpan()[..charsRead]; 19 | int[] values = new int[4]; 20 | int i = 0; 21 | foreach (var value in text) 22 | { 23 | if (char.IsDigit(value)) 24 | { 25 | values[i] *= 10; 26 | values[i] += value - '0'; 27 | } 28 | else 29 | if (value == ',') 30 | i++; 31 | } 32 | ArrayPool.Shared.Return(buffer); 33 | return new Rectangle(values[0], values[1], values[2], values[3]); 34 | } 35 | 36 | return JsonSerializer.Deserialize(ref reader, options); 37 | } 38 | 39 | public override void Write(Utf8JsonWriter writer, Rectangle value, JsonSerializerOptions options) 40 | => JsonSerializer.Serialize(writer, value, value.GetType(), options); 41 | } 42 | -------------------------------------------------------------------------------- /CryptoScanBot.Core/Model/CryptoAccount.cs: -------------------------------------------------------------------------------- 1 | using CryptoScanBot.Core.Account; 2 | using CryptoScanBot.Core.Enums; 3 | 4 | using Dapper.Contrib.Extensions; 5 | 6 | namespace CryptoScanBot.Core.Model; 7 | 8 | [Table("TradeAccount")] 9 | public class CryptoAccount 10 | { 11 | [Key] 12 | public int Id { get; set; } 13 | 14 | public int ExchangeId { get; set; } 15 | [Computed] 16 | public virtual required CryptoExchange Exchange { get; set; } 17 | 18 | public CryptoAccountType AccountType { get; set; } 19 | 20 | public bool CanTrade { get; set; } 21 | 22 | // All kind of data for this account 23 | // (emulator can run simultanious with scanner, paper or exchange trading) 24 | [Computed] 25 | public AccountData Data { get; } = new(); 26 | 27 | } 28 | -------------------------------------------------------------------------------- /CryptoScanBot.Core/Model/CryptoAsset.cs: -------------------------------------------------------------------------------- 1 | using Dapper.Contrib.Extensions; 2 | 3 | namespace CryptoScanBot.Core.Model; 4 | 5 | [Table("Asset")] 6 | public class CryptoAsset 7 | { 8 | [Key] 9 | public int Id { get; set; } 10 | 11 | public int TradeAccountId { get; set; } 12 | 13 | // De basismunt (BTC, ETH, USDT enzovoort) 14 | public string Name { get; set; } = ""; 15 | 16 | public decimal Total { get; set; } 17 | public decimal Free { get; set; } 18 | public decimal Locked { get; set; } 19 | } 20 | -------------------------------------------------------------------------------- /CryptoScanBot.Core/Model/CryptoBalance.cs: -------------------------------------------------------------------------------- 1 | using Dapper.Contrib.Extensions; 2 | 3 | namespace CryptoScanBot.Core.Model; 4 | 5 | [Table("Balance")] 6 | public class CryptoBalance 7 | { 8 | [Key] 9 | public int Id { get; set; } 10 | 11 | //[Required] 12 | public DateTime EventTime { get; set; } 13 | 14 | //[Required] 15 | public string Name { get; set; } = ""; 16 | 17 | //[Required] 18 | public decimal Price { get; set; } 19 | 20 | //[Required] 21 | // Negatief voor een verkoop 22 | public decimal Quantity { get; set; } 23 | 24 | //[Required] 25 | // De Pice * Quantity 26 | public decimal QuoteQuantity { get; set; } 27 | public decimal UsdtValue { get; set; } 28 | 29 | public decimal InvestedQuantity { get; set; } 30 | public decimal InvestedValue { get; set; } 31 | } 32 | -------------------------------------------------------------------------------- /CryptoScanBot.Core/Model/CryptoExchange.cs: -------------------------------------------------------------------------------- 1 | using CryptoScanBot.Core.Enums; 2 | 3 | using Dapper.Contrib.Extensions; 4 | 5 | namespace CryptoScanBot.Core.Model; 6 | 7 | [Table("Exchange")] 8 | public class CryptoExchange 9 | { 10 | [Key] 11 | public int Id { get; set; } 12 | public required string Name { get; set; } 13 | public bool IsSupported { get; set; } 14 | 15 | // Datum dat de laatste keer de exchange informatie is opgehaald 16 | public DateTime? LastTimeFetched { get; set; } 17 | 18 | public decimal FeeRate { get; set; } 19 | 20 | public CryptoExchangeType ExchangeType { get; set; } 21 | public CryptoTradingType TradingType { get; set; } 22 | 23 | // Coins indexed on id and name 24 | [Computed] 25 | public SortedList SymbolListId { get; } = []; 26 | 27 | [Computed] 28 | public SortedList SymbolListName { get; } = []; 29 | 30 | 31 | 32 | /// 33 | /// Clear symbol information (after change of exchange) 34 | /// 35 | public void Clear() 36 | { 37 | SymbolListId.Clear(); 38 | SymbolListName.Clear(); 39 | } 40 | 41 | } -------------------------------------------------------------------------------- /CryptoScanBot.Core/Model/CryptoInterval.cs: -------------------------------------------------------------------------------- 1 | using CryptoScanBot.Core.Enums; 2 | 3 | using Dapper.Contrib.Extensions; 4 | 5 | namespace CryptoScanBot.Core.Model; 6 | 7 | [Table("Interval")] 8 | public class CryptoInterval 9 | { 10 | [Key] 11 | public int Id { get; set; } 12 | /// 13 | /// Interval name 14 | /// 15 | public required string Name { get; set; } 16 | 17 | /// 18 | /// Interval enumeration 19 | /// 20 | public CryptoIntervalPeriod IntervalPeriod { get; set; } 21 | 22 | /// 23 | /// Number of seconds for this interval 24 | /// 25 | public int Duration { get; set; } 26 | 27 | /// 28 | /// Verwijzing naar een ander interval waar deze uit op te bouwen is 29 | /// 30 | public int? ConstructFromId { get; set; } 31 | [Computed] 32 | public virtual CryptoInterval? ConstructFrom { get; set; } 33 | 34 | 35 | public static CryptoInterval CreateInterval(CryptoIntervalPeriod intervalPeriod, string name, int duration, CryptoInterval? constructFrom) 36 | { 37 | CryptoInterval cryptoInterval = new() 38 | { 39 | IntervalPeriod = intervalPeriod, 40 | Name = name, 41 | Duration = duration, 42 | ConstructFrom = constructFrom 43 | }; 44 | return cryptoInterval; 45 | } 46 | } -------------------------------------------------------------------------------- /CryptoScanBot.Core/Model/CryptoLiveData.cs: -------------------------------------------------------------------------------- 1 | using CryptoScanBot.Core.Signal; 2 | 3 | using Dapper.Contrib.Extensions; 4 | 5 | namespace CryptoScanBot.Core.Model; 6 | 7 | public class CryptoLiveData 8 | { 9 | public required CryptoSymbol Symbol { get; set; } 10 | public required CryptoInterval Interval { get; set; } 11 | public required CryptoCandle Candle { get; set; } 12 | } 13 | -------------------------------------------------------------------------------- /CryptoScanBot.Core/Model/CryptoOrder.cs: -------------------------------------------------------------------------------- 1 | using CryptoScanBot.Core.Enums; 2 | 3 | using Dapper.Contrib.Extensions; 4 | 5 | namespace CryptoScanBot.Core.Model; 6 | 7 | [Table("[Order]")] 8 | public class CryptoOrder 9 | { 10 | [Key] 11 | public int Id { get; set; } 12 | 13 | public DateTime CreateTime { get; set; } 14 | public DateTime UpdateTime { get; set; } 15 | 16 | public int TradeAccountId { get; set; } 17 | [Computed] 18 | public virtual required CryptoAccount TradeAccount { get; set; } 19 | 20 | public int ExchangeId { get; set; } 21 | [Computed] 22 | public virtual required CryptoExchange Exchange { get; set; } 23 | 24 | public int SymbolId { get; set; } 25 | [Computed] 26 | public virtual required CryptoSymbol Symbol { get; set; } 27 | 28 | public string? OrderId { get; set; } 29 | public CryptoOrderSide Side { get; set; } 30 | public CryptoOrderType Type { get; set; } 31 | public CryptoOrderStatus Status { get; set; } 32 | 33 | public decimal? Price { get; set; } 34 | public decimal Quantity { get; set; } 35 | public decimal QuoteQuantity { get; set; } 36 | 37 | public decimal? AveragePrice { get; set; } 38 | public decimal? QuantityFilled { get; set; } 39 | public decimal? QuoteQuantityFilled { get; set; } 40 | 41 | public decimal? Commission { get; set; } 42 | public string? CommissionAsset { get; set; } 43 | } 44 | 45 | -------------------------------------------------------------------------------- /CryptoScanBot.Core/Model/CryptoOrderList.cs: -------------------------------------------------------------------------------- 1 | using CryptoScanBot.Core.Core; 2 | 3 | namespace CryptoScanBot.Core.Model; 4 | 5 | public class CryptoOrderList : SortedList 6 | { 7 | public void AddOrder(CryptoOrder order, bool log = true) 8 | { 9 | if (GlobalData.TradeAccountList.TryGetValue(order.TradeAccountId, out CryptoAccount? tradeAccount)) 10 | { 11 | order.TradeAccount = tradeAccount; 12 | 13 | if (GlobalData.ExchangeListId.TryGetValue(order.ExchangeId, out Model.CryptoExchange? exchange)) 14 | { 15 | order.Exchange = exchange; 16 | 17 | if (exchange.SymbolListId.TryGetValue(order.SymbolId, out CryptoSymbol? symbol)) 18 | { 19 | order.Symbol = symbol; 20 | 21 | if (order.OrderId != null && !ContainsKey(order.OrderId)) 22 | { 23 | this.TryAdd(order.OrderId, order); 24 | if (log) 25 | GlobalData.AddTextToLogTab($"{order.Symbol.Name} added order {order.CreateTime} {order.OrderId} {order.Status} (#{order.Id})"); 26 | } 27 | 28 | } 29 | 30 | } 31 | } 32 | } 33 | 34 | public CryptoOrder? Find(string orderId) 35 | { 36 | if (TryGetValue(orderId, out CryptoOrder? order)) 37 | return order; 38 | else 39 | return null; 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /CryptoScanBot.Core/Model/CryptoQuoteData.cs: -------------------------------------------------------------------------------- 1 | using CryptoScanBot.Core.Json; 2 | 3 | using Dapper.Contrib.Extensions; 4 | 5 | using System.Text.Json.Serialization; 6 | 7 | namespace CryptoScanBot.Core.Model; 8 | 9 | public class CryptoQuoteData 10 | { 11 | public required string Name { get; set; } 12 | 13 | public string DisplayFormat { get; set; } = "N8"; 14 | 15 | // Basecoin data 16 | public bool FetchCandles { get; set; } 17 | public decimal MinimalVolume { get; set; } 18 | public decimal MinimalPrice { get; set; } 19 | // Trading: The initial entry amount 20 | public decimal EntryAmount { get; set; } 21 | // Trading: The initial entry percentage of PF 22 | public decimal EntryPercentage { get; set; } 23 | // Color of the base coin in signal grid 24 | [JsonConverter(typeof(ColorConverter))] 25 | public System.Drawing.Color DisplayColor { get; set; } = System.Drawing.Color.White; 26 | 27 | // List of symbols (for this quote) 28 | [Computed] 29 | [JsonIgnore] 30 | public List SymbolList { get; } = []; 31 | } 32 | 33 | 34 | -------------------------------------------------------------------------------- /CryptoScanBot.Core/Model/CryptoSequence.cs: -------------------------------------------------------------------------------- 1 | namespace CryptoScanBot.Core.Model; 2 | 3 | using Dapper.Contrib.Extensions; 4 | 5 | [Table("Sequence")] 6 | public class CryptoSequence 7 | { 8 | [Key] 9 | public int Id { get; set; } 10 | public string Name { get; set; } = ""; 11 | } -------------------------------------------------------------------------------- /CryptoScanBot.Core/Model/CryptoSymbolInterval.cs: -------------------------------------------------------------------------------- 1 | using CryptoScanBot.Core.Enums; 2 | 3 | namespace CryptoScanBot.Core.Model; 4 | 5 | // An in-memory class 6 | public class CryptoSymbolInterval 7 | { 8 | public virtual required CryptoInterval Interval { get; set; } 9 | public required CryptoIntervalPeriod IntervalPeriod { get; set; } 10 | 11 | // The last synchronized candle with the exchange (without gaps) 12 | public long? LastCandleSynchronized { get; set; } 13 | 14 | // The candles for this interval 15 | public CryptoCandleList CandleList { get; set; } = []; 16 | 17 | // The last signals generated for this interval 18 | public List SignalList { get; set; } = []; 19 | } 20 | -------------------------------------------------------------------------------- /CryptoScanBot.Core/Model/CryptoTrade.cs: -------------------------------------------------------------------------------- 1 | using Dapper.Contrib.Extensions; 2 | 3 | namespace CryptoScanBot.Core.Model; 4 | 5 | [Table("Trade")] 6 | public class CryptoTrade 7 | { 8 | [Key] 9 | public int Id { get; set; } 10 | 11 | public DateTime TradeTime { get; set; } 12 | 13 | public int TradeAccountId { get; set; } 14 | [Computed] 15 | public required CryptoAccount? TradeAccount { get; set; } 16 | 17 | public int ExchangeId { get; set; } 18 | [Computed] 19 | public required CryptoExchange? Exchange { get; set; } 20 | 21 | public int SymbolId { get; set; } 22 | [Computed] 23 | public required CryptoSymbol? Symbol { get; set; } 24 | 25 | public decimal Price { get; set; } 26 | public decimal Quantity { get; set; } // De gevulde quantity 27 | public decimal QuoteQuantity { get; set; } // Filled quantity * price 28 | 29 | 30 | public decimal Commission { get; set; } 31 | public string CommissionAsset { get; set; } = ""; 32 | 33 | public string TradeId { get; set; } = ""; 34 | public string OrderId { get; set; } = ""; 35 | } 36 | -------------------------------------------------------------------------------- /CryptoScanBot.Core/Model/CryptoTradeList.cs: -------------------------------------------------------------------------------- 1 | using CryptoScanBot.Core.Core; 2 | 3 | namespace CryptoScanBot.Core.Model; 4 | 5 | public class CryptoTradeList : SortedList 6 | { 7 | public void AddTrade(CryptoTrade trade, bool log = true) 8 | { 9 | if (GlobalData.TradeAccountList.TryGetValue(trade.TradeAccountId, out CryptoAccount? tradeAccount)) 10 | { 11 | trade.TradeAccount = tradeAccount; 12 | 13 | if (GlobalData.ExchangeListId.TryGetValue(trade.ExchangeId, out Model.CryptoExchange? exchange)) 14 | { 15 | trade.Exchange = exchange; 16 | 17 | if (exchange.SymbolListId.TryGetValue(trade.SymbolId, out CryptoSymbol? symbol)) 18 | { 19 | trade.Symbol = symbol; 20 | 21 | if (!ContainsKey(trade.TradeId)) 22 | { 23 | Add(trade.TradeId, trade); 24 | if (log) 25 | GlobalData.AddTextToLogTab($"{trade.Symbol.Name} order {trade.TradeTime} {trade.OrderId} added trade {trade.TradeId} (#{trade.Id})"); 26 | } 27 | } 28 | 29 | } 30 | } 31 | } 32 | 33 | public CryptoTrade? Find(string tradeId) 34 | { 35 | if (TryGetValue(tradeId, out CryptoTrade? trade)) 36 | return trade!; 37 | else 38 | return null; 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /CryptoScanBot.Core/Model/CryptoVersion.cs: -------------------------------------------------------------------------------- 1 | using Dapper.Contrib.Extensions; 2 | 3 | 4 | [Table("Version")] 5 | public class CryptoVersion 6 | { 7 | [Key] 8 | public int Id { get; set; } 9 | public int Version { get; set; } 10 | } -------------------------------------------------------------------------------- /CryptoScanBot.Core/Model/CryptoZone.cs: -------------------------------------------------------------------------------- 1 | using CryptoScanBot.Core.Enums; 2 | 3 | using Dapper.Contrib.Extensions; 4 | 5 | namespace CryptoScanBot.Core.Model; 6 | 7 | public enum CryptoZoneKind 8 | { 9 | DominantLevel = 1, // Or LiquidityZone..? 10 | FairValueGap = 2, 11 | } 12 | 13 | [Table("Zone")] 14 | public class CryptoZone 15 | { 16 | [Key] 17 | public int Id { get; set; } 18 | 19 | public int AccountId { get; set; } 20 | [Computed] 21 | public required virtual CryptoAccount Account { get; set; } 22 | 23 | public required int ExchangeId { get; set; } 24 | [Computed] 25 | public required virtual CryptoExchange Exchange { get; set; } 26 | 27 | public required int SymbolId { get; set; } 28 | [Computed] 29 | public required virtual CryptoSymbol Symbol { get; set; } 30 | 31 | public required CryptoZoneKind Kind { get; set; } 32 | public required CryptoTradeSide Side { get; set; } 33 | 34 | // Created on.. 35 | public required DateTime CreateTime { get; set; } 36 | 37 | public long? OpenTime { get; set; } // Zone starts on this date, for limited types of zones 38 | public required decimal Top { get; set; } 39 | public required decimal Bottom { get; set; } 40 | public long? CloseTime { get; set; } // Zone ends on this date 41 | 42 | // Create a signal when this price triggers (once) 43 | public DateTime? AlarmDate { get; set; } 44 | 45 | public long? LastSignalDate { get; set; } 46 | 47 | // Percentage of the zone or other text 48 | public string Description { get; set; } = ""; 49 | 50 | public bool IsValid { get; set; } 51 | } 52 | -------------------------------------------------------------------------------- /CryptoScanBot.Core/Settings/SettingsAltradyApi.cs: -------------------------------------------------------------------------------- 1 | using CryptoScanBot.Core.Json; 2 | 3 | using System.Text.Json.Serialization; 4 | 5 | namespace CryptoScanBot.Core.Settings; 6 | 7 | [Serializable] 8 | public class SettingsAltradyApi 9 | { 10 | [JsonConverter(typeof(SecureStringConverter))] 11 | public string Key { get; set; } = ""; 12 | [JsonConverter(typeof(SecureStringConverter))] 13 | public string Secret { get; set; } = ""; 14 | } -------------------------------------------------------------------------------- /CryptoScanBot.Core/Settings/SettingsBackTest.cs: -------------------------------------------------------------------------------- 1 | namespace CryptoScanBot.Core.Settings; 2 | 3 | [Serializable] 4 | public class SettingsBackTest 5 | { 6 | public string BackTestSymbol { get; set; } = "BTCUSDT"; 7 | //public string BackTestInterval { get; set; } = "1M"; 8 | public DateTime BackTestStartTime { get; set; } = DateTime.Now; 9 | public DateTime BackTestEndTime { get; set; } = DateTime.Now; 10 | //public CryptoOrderSide BackTestMode { get; set; } = CryptoOrderSide.Buy; 11 | //public CryptoSignalStrategy BackTestAlgoritm { get; set; } = CryptoSignalStrategy.Sbm1; 12 | } 13 | 14 | -------------------------------------------------------------------------------- /CryptoScanBot.Core/Settings/SettingsBalanceBot.cs: -------------------------------------------------------------------------------- 1 | namespace CryptoScanBot.Core.Settings; 2 | 3 | #if balancing 4 | [Serializable] 5 | public class BalanceSymbol 6 | { 7 | public string Symbol { get; set; } 8 | public decimal Percentage { get; set; } 9 | } 10 | 11 | [Serializable] 12 | public class SettingsBalanceBot 13 | { 14 | public bool Active { get; set; } 15 | public bool UseMarketOrder { get; set; } 16 | public bool ShowAdviceOnly { get; set; } 17 | public decimal MinimalBuyBarometer { get; set; } 18 | public decimal MinimalSellBarometer { get; set; } 19 | 20 | public int IntervalPeriod { get; set; } 21 | 22 | // Het DCA percentage bijkopen 23 | public decimal BuyThresholdPercentage { get; set; } 24 | // Het DCA percentage voor verkopen 25 | public decimal SellThresholdPercentage { get; set; } 26 | 27 | // Het start bedrag (winst berekenen), discutabel want ik krijg dat niet voor elkaar..(?) 28 | public decimal StartAmount { get; set; } 29 | 30 | 31 | // Lijst van symbolen met de gewenste verdeling 32 | public List CoinList = new List(); 33 | 34 | public SettingsBalanceBot() 35 | { 36 | // ***************************************** 37 | // Balance bot settings 38 | // ***************************************** 39 | Active = false; 40 | UseMarketOrder = true; 41 | ShowAdviceOnly = false; 42 | 43 | IntervalPeriod = 1; 44 | 45 | BuyThresholdPercentage = 2.5m; 46 | SellThresholdPercentage = 2.5m; 47 | 48 | MinimalBuyBarometer = -999; 49 | MinimalSellBarometer = -999; 50 | } 51 | } 52 | #endif -------------------------------------------------------------------------------- /CryptoScanBot.Core/Settings/SettingsBasic.cs: -------------------------------------------------------------------------------- 1 | using CryptoScanBot.Core.Model; 2 | 3 | namespace CryptoScanBot.Core.Settings; 4 | 5 | [Serializable] 6 | public class SettingsBasic 7 | { 8 | /// 9 | /// Standaard instellingen 10 | /// 11 | public SettingsGeneral General { get; set; } = new(); 12 | 13 | /// 14 | /// Scanner gerelateerde instellingen 15 | /// 16 | public SettingsSignal Signal { get; set; } = new(); 17 | 18 | /// 19 | /// Trading gerelateerde instellingen 20 | /// 21 | public SettingsTrading Trading { get; set; } = new(); 22 | 23 | /// 24 | /// Balanceer instellingen (restant van oude tool) 25 | /// 26 | //public SettingsBalanceBot BalanceBot { get; set; } = new(); 27 | 28 | /// 29 | /// Welke basis munten willen we gebruiken 30 | /// 31 | public SortedList QuoteCoins { get; set; } = []; 32 | 33 | // Als de whitelist gevuld is dan moet de symbol voorkomen in de lijst (anders geen meldingen) 34 | public List WhiteListOversold { get; set; } = []; 35 | 36 | // Als de symbol in de blacklist voorkomt worden er geen meldingen voor deze munt gemaakt 37 | public List BlackListOversold { get; set; } = []; 38 | 39 | // Als de whitelist gevuld is dan moet de symbol voorkomen in de lijst (anders geen meldingen) 40 | public List WhiteListOverbought { get; set; } = []; 41 | 42 | // Als de symbol in de blacklist voorkomt worden er geen meldingen voor deze munt gemaakt 43 | public List BlackListOverbought { get; set; } = []; 44 | 45 | /// Instellingen voor het uitvoeren backtest (work in progres) 46 | public SettingsBackTest BackTest { get; set; } = new(); 47 | 48 | // What symbols to show 49 | public List ShowSymbolInformation { get; set; } = new(["BTC", "PAXG", "ETH", "XRP", "SOL", "ADA"]); 50 | 51 | public SettingsBasic() 52 | { 53 | // Als default toch iets inschieten 54 | CryptoQuoteData quoteData = new() 55 | { 56 | Name = "USDT", 57 | FetchCandles = true, 58 | MinimalVolume = 4500000, 59 | }; 60 | 61 | QuoteCoins.Add(quoteData.Name, quoteData); 62 | } 63 | } -------------------------------------------------------------------------------- /CryptoScanBot.Core/Settings/SettingsExchangeApi.cs: -------------------------------------------------------------------------------- 1 | using CryptoScanBot.Core.Json; 2 | 3 | using System.Text.Json.Serialization; 4 | 5 | namespace CryptoScanBot.Core.Settings; 6 | 7 | [Serializable] 8 | public class SettingsExchangeApi 9 | { 10 | // TODO: Iedere exchange heeft 0 of meer key/secret's 11 | [JsonConverter(typeof(SecureStringConverter))] 12 | public string Key { get; set; } = ""; 13 | [JsonConverter(typeof(SecureStringConverter))] 14 | public string Secret { get; set; } = ""; 15 | [JsonConverter(typeof(SecureStringConverter))] 16 | public string PassPhrase { get; set; } = ""; // Kucoin 17 | } -------------------------------------------------------------------------------- /CryptoScanBot.Core/Settings/SettingsLinksAltrady.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CryptoMarius/CryptoScanBot/6beada462008b1e92b5cf55fd764c70d8c70a604/CryptoScanBot.Core/Settings/SettingsLinksAltrady.jpg -------------------------------------------------------------------------------- /CryptoScanBot.Core/Settings/SettingsTelegram.cs: -------------------------------------------------------------------------------- 1 | using CryptoScanBot.Core.Json; 2 | 3 | using System.Text.Json.Serialization; 4 | 5 | namespace CryptoScanBot.Core.Settings; 6 | 7 | [Serializable] 8 | public class SettingsTelegram 9 | { 10 | [JsonConverter(typeof(SecureStringConverter))] 11 | public string Token { get; set; } = ""; 12 | [JsonConverter(typeof(SecureStringConverter))] 13 | public string ChatId { get; set; } = ""; 14 | 15 | public bool EmojiInTrend { get; set; } = true; 16 | public bool SendSignalsToTelegram { get; set; } = false; 17 | } -------------------------------------------------------------------------------- /CryptoScanBot.Core/Settings/SettingsTextual.cs: -------------------------------------------------------------------------------- 1 | namespace CryptoScanBot.Core.Settings; 2 | 3 | // Common storage for signal (long/short) and trading (long/short) 4 | [Serializable] 5 | public class SettingsTextual 6 | { 7 | public SettingsTextual() 8 | { 9 | Interval.Add("1m"); 10 | Interval.Add("2m"); 11 | Interval.Add("3m"); 12 | 13 | Strategy.Add("sbm1"); 14 | Strategy.Add("sbm2"); 15 | Strategy.Add("sbm3"); 16 | Strategy.Add("stobb"); 17 | } 18 | 19 | // Op welke interval 20 | public List Interval { get; set; } = []; 21 | 22 | // Op welke strategie 23 | public List Strategy { get; set; } = []; 24 | 25 | // Op welk interval moet de trend bull of bear zijn 26 | public SettingsTextualIntervalTrend IntervalTrend = new(); 27 | 28 | // Via interval + Value (range needed?) 29 | public SettingsTextualBarometer Barometer = new(); 30 | 31 | // Market trend percentage 32 | public SettingsTextualMarketTrend MarketTrend = new(); 33 | } 34 | 35 | 36 | [Serializable] 37 | public class SettingsTextualBarometer 38 | { 39 | public Dictionary List { get; set; } = []; 40 | public bool Log = true; 41 | } 42 | 43 | [Serializable] 44 | public class SettingsTextualMarketTrend 45 | { 46 | public List<(decimal minValue, decimal maxValue)> List { get; set; } = []; 47 | public bool Log = true; 48 | } 49 | 50 | [Serializable] 51 | public class SettingsTextualIntervalTrend 52 | { 53 | public List List { get; set; } = []; 54 | public bool Log = true; 55 | } 56 | -------------------------------------------------------------------------------- /CryptoScanBot.Core/Settings/SettingsUser.cs: -------------------------------------------------------------------------------- 1 | using System.Drawing; 2 | using System.Text.Json.Serialization; 3 | 4 | namespace CryptoScanBot.Core.Settings; 5 | 6 | [Serializable] 7 | public class ColumnSetting 8 | { 9 | public int Width { get; set; } = -1; 10 | public bool Visible { get; set; } = true; 11 | public bool AlwaysVisible { get; set; } = false; 12 | } 13 | 14 | [Serializable] 15 | public class FormDimensions 16 | { 17 | [JsonConverter(typeof(Json.RectangleConverter))] 18 | public Rectangle WindowPosition { get; set; } = new Rectangle(); 19 | public int WindowState { get; set; } = 0; 20 | 21 | // mainform only 22 | public int SplitterDistance { get; set; } = 0; 23 | } 24 | 25 | [Serializable] 26 | public class SettingsUser 27 | { 28 | public FormDimensions MainForm { get; set; } = new(); 29 | public FormDimensions ChartForm { get; set; } = new(); 30 | 31 | // Saved custom colors 32 | public int[] CustomColors { get; set; } = []; 33 | 34 | // Visible columns in each grid 35 | public SortedList GridColumnsSignal { get; set; } = []; 36 | public SortedList GridColumnsSymbol { get; set; } = []; 37 | public SortedList GridColumnsPositionsOpen { get; set; } = []; 38 | public SortedList GridColumnsPositionsClosed { get; set; } = []; 39 | public SortedList GridColumnsLiveData { get; set; } = []; 40 | } 41 | 42 | -------------------------------------------------------------------------------- /CryptoScanBot.Core/Settings/Strategy/SettingsSignalStrategyBase.cs: -------------------------------------------------------------------------------- 1 | using System.Drawing; 2 | using System.Text.Json.Serialization; 3 | 4 | namespace CryptoScanBot.Core.Settings.Strategy; 5 | 6 | // Base class for the colors and soundfile 7 | 8 | [Serializable] 9 | public class SettingsSignalStrategyBase 10 | { 11 | public bool PlaySound { get; set; } = false; 12 | public bool PlaySpeech { get; set; } = false; 13 | 14 | [JsonConverter(typeof(Json.ColorConverter))] 15 | public Color ColorLong { get; set; } = Color.White; 16 | public string SoundFileLong { get; set; } = ""; 17 | //string text = ColorTranslator.ToHtml(Color); 18 | //Color color = ColorTranslator.FromHtml(text); 19 | 20 | [JsonConverter(typeof(Json.ColorConverter))] 21 | public Color ColorShort { get; set; } = Color.White; 22 | public string SoundFileShort { get; set; } = ""; 23 | 24 | 25 | //// Colors 26 | //public SettingsColor ColorLongX = new(); 27 | //public SettingsSound SoundLongX = new(); 28 | 29 | //// Sounds 30 | //public SettingsColor ColorShortX = new(); 31 | //public SettingsSound SoundShortX = new (); 32 | } 33 | -------------------------------------------------------------------------------- /CryptoScanBot.Core/Settings/Strategy/SettingsSignalStrategyFvg.cs: -------------------------------------------------------------------------------- 1 | namespace CryptoScanBot.Core.Settings.Strategy; 2 | 3 | [Serializable] 4 | public class SettingsSignalStrategyFvg : SettingsSignalStrategyBase 5 | { 6 | public bool ShowSignalsLong { get; set; } = false; 7 | public bool ShowSignalsShort { get; set; } = false; 8 | 9 | public double MinimumPercentage { get; set; } = 0.25; 10 | 11 | public SettingsSignalStrategyFvg() : base() 12 | { 13 | SoundFileLong = "sound-fvg-long.wav"; 14 | SoundFileShort = "sound-fvg-short.wav"; 15 | } 16 | 17 | } -------------------------------------------------------------------------------- /CryptoScanBot.Core/Settings/Strategy/SettingsSignalStrategyJump.cs: -------------------------------------------------------------------------------- 1 | namespace CryptoScanBot.Core.Settings.Strategy; 2 | 3 | [Serializable] 4 | public class SettingsSignalStrategyJump : SettingsSignalStrategyBase 5 | { 6 | public bool UseLowHighCalculation { get; set; } = false; 7 | public int CandlesLookbackCount { get; set; } = 5; 8 | public decimal CandlePercentage { get; set; } = 4m; 9 | 10 | public SettingsSignalStrategyJump() : base() 11 | { 12 | SoundFileLong = "sound-jump-up.wav"; 13 | SoundFileShort = "sound-jump-down.wav"; 14 | } 15 | 16 | } -------------------------------------------------------------------------------- /CryptoScanBot.Core/Settings/Strategy/SettingsSignalStrategySbm.cs: -------------------------------------------------------------------------------- 1 | namespace CryptoScanBot.Core.Settings.Strategy; 2 | 3 | [Serializable] 4 | public class SettingsSignalStrategySbm : SettingsSignalStrategyBase 5 | { 6 | // SBM1 signals 7 | public int Sbm1CandlesLookbackCount { get; set; } = 1; 8 | public bool UseLowHigh { get; set; } = false; 9 | 10 | // SBM2 signals 11 | public int Sbm2CandlesLookbackCount { get; set; } = 2; 12 | public decimal Sbm2BbPercentage { get; set; } = 2.5m; 13 | public bool Sbm2UseLowHigh { get; set; } = false; 14 | 15 | // SBM3 signals 16 | public int Sbm3CandlesLookbackCount { get; set; } = 8; 17 | public decimal Sbm3CandlesBbRecoveryPercentage { get; set; } = 225m; 18 | 19 | 20 | // SBM algemene 21 | public int CandlesForMacdRecovery { get; set; } = 2; 22 | 23 | public decimal Ma200AndMa50Percentage { get; set; } = 0.25m; 24 | public decimal Ma50AndMa20Percentage { get; set; } = 0.25m; 25 | public decimal Ma200AndMa20Percentage { get; set; } = 0.50m; 26 | 27 | public bool Ma200AndMa50Crossing { get; set; } = true; 28 | public int Ma200AndMa50Lookback { get; set; } = 30; 29 | public bool Ma50AndMa20Crossing { get; set; } = true; 30 | public int Ma50AndMa20Lookback { get; set; } = 10; 31 | public bool Ma200AndMa20Crossing { get; set; } = true; 32 | public int Ma200AndMa20Lookback { get; set; } = 15; 33 | 34 | // Het BB percentage kan via de user interface uit worden gezet (nomargin) 35 | public double BBMinPercentage { get; set; } = 1.50; 36 | public double BBMaxPercentage { get; set; } = 100.0; 37 | 38 | public SettingsSignalStrategySbm() : base() 39 | { 40 | SoundFileLong = "sound-sbm-oversold.wav"; 41 | SoundFileShort = "sound-sbm-overbought.wav"; 42 | } 43 | 44 | } -------------------------------------------------------------------------------- /CryptoScanBot.Core/Settings/Strategy/SettingsSignalStrategyStoRsi.cs: -------------------------------------------------------------------------------- 1 | namespace CryptoScanBot.Core.Settings.Strategy; 2 | 3 | [Serializable] 4 | public class SettingsSignalStrategyStoRsi : SettingsSignalStrategyBase 5 | { 6 | public double BBMinPercentage { get; set; } = 1.50; 7 | public double BBMaxPercentage { get; set; } = 100.0; 8 | 9 | public int AddRsiAmount { get; set; } = 0; 10 | public int AddStochAmount { get; set; } = 0; 11 | 12 | public bool SkipFirstSignal { get; set; } = false; 13 | public bool CheckBollingerBandsCondition { get; set; } = false; 14 | 15 | public SettingsSignalStrategyStoRsi() : base() 16 | { 17 | SoundFileLong = "sound-storsi-oversold.wav"; 18 | SoundFileShort = "sound-storsi-overbought.wav"; 19 | } 20 | 21 | } -------------------------------------------------------------------------------- /CryptoScanBot.Core/Settings/Strategy/SettingsSignalStrategyStobb.cs: -------------------------------------------------------------------------------- 1 | namespace CryptoScanBot.Core.Settings.Strategy; 2 | 3 | [Serializable] 4 | public class SettingsSignalStrategyStobb : SettingsSignalStrategyBase 5 | { 6 | // Het BB percentage kan via de user interface uit worden gezet (nomargin) 7 | public double BBMinPercentage { get; set; } = 1.50; 8 | public double BBMaxPercentage { get; set; } = 5.0; 9 | public bool UseLowHigh { get; set; } = false; 10 | //[JsonConverter(typeof(Intern.ColorConverter))] 11 | //public Color ColorStobbLong { get; set; } = Color.White; 12 | //[JsonConverter(typeof(Intern.ColorConverter))] 13 | //public Color ColorStobbShort { get; set; } = Color.White; 14 | //public bool PlaySoundStobbSignal { get; set; } = false; 15 | //public bool PlaySpeechStobbSignal { get; set; } = false; 16 | //public string SoundStobbLong { get; set; } = "sound-stobb-oversold.wav"; 17 | //public string SoundStobbShort { get; set; } = "sound-stobb-overbought.wav"; 18 | public bool IncludeRsi { get; set; } = false; 19 | public bool IncludeSoftSbm { get; set; } = false; 20 | public bool OnlyIfPreviousStobb { get; set; } = false; 21 | public bool IncludeSbmPercAndCrossing { get; set; } = false; 22 | public decimal TrendLong { get; set; } = -999m; 23 | public decimal TrendShort { get; set; } = -999m; 24 | 25 | public SettingsSignalStrategyStobb() : base() 26 | { 27 | SoundFileLong = "sound-stobb-oversold.wav"; 28 | SoundFileShort = "sound-stobb-overbought.wav"; 29 | } 30 | 31 | } -------------------------------------------------------------------------------- /CryptoScanBot.Core/Settings/Strategy/SettingsSignalStrategyZones.cs: -------------------------------------------------------------------------------- 1 | using CryptoScanBot.Core.Enums; 2 | 3 | namespace CryptoScanBot.Core.Settings.Strategy; 4 | 5 | [Serializable] 6 | public class SettingsSignalStrategyZones : SettingsSignalStrategyBase 7 | { 8 | public bool ShowSignalsLong { get; set; } = false; 9 | public bool ShowSignalsShort { get; set; } = false; 10 | 11 | public int CandleCount { get; set; } = 500; //3000; // 3000=150 day's back, 500=20.8 dagen 12 | public CryptoIntervalPeriod Interval { get; set; } = CryptoIntervalPeriod.interval1h; 13 | 14 | // Limits unzoomed box 15 | public bool ZonesApplyUnzoomed { get; set; } = false; 16 | public double MinimumUnZoomedPercentage { get; set; } = 0.0; 17 | public double MaximumUnZoomedPercentage { get; set; } = 0.0; 18 | 19 | // Limits zoomed box 20 | public bool ZoomLowerTimeFrames { get; set; } = true; 21 | public double MinimumZoomedPercentage { get; set; } = 0.2; 22 | public double MaximumZoomedPercentage { get; set; } = 0.7; 23 | 24 | // Signal percentage 25 | public decimal WarnPercentage { get; set; } = 1.0m; 26 | 27 | // Filter on start 28 | public bool ZoneStartApply { get; set; } = false; 29 | public int ZoneStartCandleCount { get; set; } = 5; // 5 candles back 30 | public double ZoneStartPercentage { get; set; } = 2.5; // % 31 | 32 | public SettingsSignalStrategyZones() : base() 33 | { 34 | SoundFileLong = "sound-zones-long.wav"; 35 | SoundFileShort = "sound-zones-short.wav"; 36 | } 37 | 38 | } -------------------------------------------------------------------------------- /CryptoScanBot.Core/Signal/AlgorithmDefinition.cs: -------------------------------------------------------------------------------- 1 | using CryptoScanBot.Core.Enums; 2 | 3 | namespace CryptoScanBot.Core.Signal; 4 | 5 | // Class for registering all algorithms 6 | public class AlgorithmDefinition 7 | { 8 | public required string Name { get; set; } 9 | public required CryptoSignalStrategy Strategy { get; set; } 10 | public required Type? AnalyzeLongType { get; set; } 11 | public required Type? AnalyzeShortType { get; set; } 12 | } 13 | -------------------------------------------------------------------------------- /CryptoScanBot.Core/Signal/Momentum/SignalSbm1Long.cs: -------------------------------------------------------------------------------- 1 | using CryptoScanBot.Core.Core; 2 | using CryptoScanBot.Core.Enums; 3 | using CryptoScanBot.Core.Model; 4 | 5 | namespace CryptoScanBot.Core.Signal.Momentum; 6 | 7 | public class SignalSbm1Long : SignalSbmBaseLong 8 | { 9 | public SignalSbm1Long(CryptoAccount account, CryptoSymbol symbol, CryptoInterval interval, CryptoCandle candle) : base(account, symbol, interval, candle) 10 | { 11 | SignalSide = CryptoTradeSide.Long; 12 | SignalStrategy = CryptoSignalStrategy.Sbm1; 13 | } 14 | 15 | 16 | public bool HadStobbInThelastXCandles(int candleCount) 17 | { 18 | // Is de prijs onlangs dicht bij de onderste bb geweest? 19 | CryptoCandle? last = CandleLast; 20 | while (candleCount > 0) 21 | { 22 | // Er een candle onder de bb opent of sluit & een oversold situatie (beide moeten onder de 20 zitten) 23 | if (last!.IsBelowBollingerBands(GlobalData.Settings.Signal.Sbm.UseLowHigh) && last!.IsStochOversold()) 24 | return true; 25 | 26 | if (!GetPrevCandle(last, out last)) 27 | return false; 28 | candleCount--; 29 | } 30 | 31 | return false; 32 | } 33 | 34 | 35 | 36 | public override bool IsSignal() 37 | { 38 | if (!base.IsSignal()) 39 | return false; 40 | 41 | if (!HadStobbInThelastXCandles(GlobalData.Settings.Signal.Sbm.Sbm1CandlesLookbackCount)) 42 | { 43 | ExtraText = "geen stob in de laatste x candles"; 44 | return false; 45 | } 46 | 47 | return true; 48 | } 49 | 50 | 51 | } 52 | -------------------------------------------------------------------------------- /CryptoScanBot.Core/Signal/Momentum/SignalSbm1Short.cs: -------------------------------------------------------------------------------- 1 | using CryptoScanBot.Core.Core; 2 | using CryptoScanBot.Core.Enums; 3 | using CryptoScanBot.Core.Model; 4 | 5 | namespace CryptoScanBot.Core.Signal.Momentum; 6 | 7 | public class SignalSbm1Short : SignalSbmBaseShort 8 | { 9 | public SignalSbm1Short(CryptoAccount account, CryptoSymbol symbol, CryptoInterval interval, CryptoCandle candle) : base(account, symbol, interval, candle) 10 | { 11 | SignalSide = CryptoTradeSide.Short; 12 | SignalStrategy = CryptoSignalStrategy.Sbm1; 13 | } 14 | 15 | 16 | public bool HadStobbInThelastXCandles(int candleCount) 17 | { 18 | // Is de prijs onlangs dicht bij de onderste bb geweest? 19 | CryptoCandle? last = CandleLast; 20 | while (candleCount > 0) 21 | { 22 | if (last == null) 23 | return false; 24 | // Er een candle onder de bb opent of sluit & een overbought situatie (beide moeten onder de 20 zitten) 25 | if (last!.IsAboveBollingerBands(GlobalData.Settings.Signal.Sbm.UseLowHigh) && last.IsStochOverbought()) 26 | return true; 27 | 28 | if (!GetPrevCandle(last, out last)) 29 | return false; 30 | candleCount--; 31 | } 32 | 33 | return false; 34 | } 35 | 36 | 37 | 38 | public override bool IsSignal() 39 | { 40 | if (!base.IsSignal()) 41 | return false; 42 | 43 | if (!HadStobbInThelastXCandles(GlobalData.Settings.Signal.Sbm.Sbm1CandlesLookbackCount)) 44 | { 45 | ExtraText = "geen stob in de laatste x candles"; 46 | return false; 47 | } 48 | 49 | return true; 50 | } 51 | 52 | 53 | } 54 | -------------------------------------------------------------------------------- /CryptoScanBot.Core/Signal/Momentum/SignalSbm2Long.cs: -------------------------------------------------------------------------------- 1 | using CryptoScanBot.Core.Core; 2 | using CryptoScanBot.Core.Enums; 3 | using CryptoScanBot.Core.Model; 4 | 5 | namespace CryptoScanBot.Core.Signal.Momentum; 6 | 7 | public class SignalSbm2Long : SignalSbmBaseLong 8 | { 9 | public SignalSbm2Long(CryptoAccount account, CryptoSymbol symbol, CryptoInterval interval, CryptoCandle candle) : base(account, symbol, interval, candle) 10 | { 11 | SignalSide = CryptoTradeSide.Long; 12 | SignalStrategy = CryptoSignalStrategy.Sbm2; 13 | } 14 | 15 | 16 | public override bool IsSignal() 17 | { 18 | if (!base.IsSignal()) 19 | return false; 20 | 21 | if (!IsInLowerPartOfBollingerBands(GlobalData.Settings.Signal.Sbm.Sbm2CandlesLookbackCount, GlobalData.Settings.Signal.Sbm.Sbm2BbPercentage)) 22 | { 23 | ExtraText = "geen lage prijs in de laatste x candles"; 24 | return false; 25 | } 26 | 27 | return true; 28 | } 29 | 30 | 31 | } 32 | -------------------------------------------------------------------------------- /CryptoScanBot.Core/Signal/Momentum/SignalSbm2Short.cs: -------------------------------------------------------------------------------- 1 | using CryptoScanBot.Core.Core; 2 | using CryptoScanBot.Core.Enums; 3 | using CryptoScanBot.Core.Model; 4 | 5 | namespace CryptoScanBot.Core.Signal.Momentum; 6 | 7 | public class SignalSbm2Short : SignalSbmBaseShort 8 | { 9 | public SignalSbm2Short(CryptoAccount account, CryptoSymbol symbol, CryptoInterval interval, CryptoCandle candle) : base(account, symbol, interval, candle) 10 | { 11 | SignalSide = CryptoTradeSide.Short; 12 | SignalStrategy = CryptoSignalStrategy.Sbm2; 13 | } 14 | 15 | 16 | public override bool IsSignal() 17 | { 18 | if (!base.IsSignal()) 19 | return false; 20 | 21 | if (!IsInUpperPartOfBollingerBands(GlobalData.Settings.Signal.Sbm.Sbm2CandlesLookbackCount, GlobalData.Settings.Signal.Sbm.Sbm2BbPercentage)) 22 | { 23 | ExtraText = "geen hoge prijs in de laatste x candles"; 24 | return false; 25 | } 26 | 27 | return true; 28 | } 29 | 30 | 31 | } 32 | -------------------------------------------------------------------------------- /CryptoScanBot.Core/Sounds/Old/sound-jump-down.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CryptoMarius/CryptoScanBot/6beada462008b1e92b5cf55fd764c70d8c70a604/CryptoScanBot.Core/Sounds/Old/sound-jump-down.wav -------------------------------------------------------------------------------- /CryptoScanBot.Core/Sounds/Old/sound-jump-up.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CryptoMarius/CryptoScanBot/6beada462008b1e92b5cf55fd764c70d8c70a604/CryptoScanBot.Core/Sounds/Old/sound-jump-up.wav -------------------------------------------------------------------------------- /CryptoScanBot.Core/Sounds/Old/sound-sbm-overbought.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CryptoMarius/CryptoScanBot/6beada462008b1e92b5cf55fd764c70d8c70a604/CryptoScanBot.Core/Sounds/Old/sound-sbm-overbought.wav -------------------------------------------------------------------------------- /CryptoScanBot.Core/Sounds/Old/sound-sbm-oversold.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CryptoMarius/CryptoScanBot/6beada462008b1e92b5cf55fd764c70d8c70a604/CryptoScanBot.Core/Sounds/Old/sound-sbm-oversold.wav -------------------------------------------------------------------------------- /CryptoScanBot.Core/Sounds/Old/sound-stobb-overbought.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CryptoMarius/CryptoScanBot/6beada462008b1e92b5cf55fd764c70d8c70a604/CryptoScanBot.Core/Sounds/Old/sound-stobb-overbought.wav -------------------------------------------------------------------------------- /CryptoScanBot.Core/Sounds/Old/sound-stobb-oversold.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CryptoMarius/CryptoScanBot/6beada462008b1e92b5cf55fd764c70d8c70a604/CryptoScanBot.Core/Sounds/Old/sound-stobb-oversold.wav -------------------------------------------------------------------------------- /CryptoScanBot.Core/Sounds/Old/sound-storsi-overbought.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CryptoMarius/CryptoScanBot/6beada462008b1e92b5cf55fd764c70d8c70a604/CryptoScanBot.Core/Sounds/Old/sound-storsi-overbought.wav -------------------------------------------------------------------------------- /CryptoScanBot.Core/Sounds/Old/sound-storsi-oversold.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CryptoMarius/CryptoScanBot/6beada462008b1e92b5cf55fd764c70d8c70a604/CryptoScanBot.Core/Sounds/Old/sound-storsi-oversold.wav -------------------------------------------------------------------------------- /CryptoScanBot.Core/Sounds/Other/aksu.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CryptoMarius/CryptoScanBot/6beada462008b1e92b5cf55fd764c70d8c70a604/CryptoScanBot.Core/Sounds/Other/aksu.wav -------------------------------------------------------------------------------- /CryptoScanBot.Core/Sounds/Other/ball_bearing.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CryptoMarius/CryptoScanBot/6beada462008b1e92b5cf55fd764c70d8c70a604/CryptoScanBot.Core/Sounds/Other/ball_bearing.wav -------------------------------------------------------------------------------- /CryptoScanBot.Core/Sounds/Other/bell_sound.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CryptoMarius/CryptoScanBot/6beada462008b1e92b5cf55fd764c70d8c70a604/CryptoScanBot.Core/Sounds/Other/bell_sound.wav -------------------------------------------------------------------------------- /CryptoScanBot.Core/Sounds/Other/boing_sound_effect.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CryptoMarius/CryptoScanBot/6beada462008b1e92b5cf55fd764c70d8c70a604/CryptoScanBot.Core/Sounds/Other/boing_sound_effect.wav -------------------------------------------------------------------------------- /CryptoScanBot.Core/Sounds/Other/boxing_bell.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CryptoMarius/CryptoScanBot/6beada462008b1e92b5cf55fd764c70d8c70a604/CryptoScanBot.Core/Sounds/Other/boxing_bell.wav -------------------------------------------------------------------------------- /CryptoScanBot.Core/Sounds/Other/cool.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CryptoMarius/CryptoScanBot/6beada462008b1e92b5cf55fd764c70d8c70a604/CryptoScanBot.Core/Sounds/Other/cool.wav -------------------------------------------------------------------------------- /CryptoScanBot.Core/Sounds/Other/discord_halloween.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CryptoMarius/CryptoScanBot/6beada462008b1e92b5cf55fd764c70d8c70a604/CryptoScanBot.Core/Sounds/Other/discord_halloween.wav -------------------------------------------------------------------------------- /CryptoScanBot.Core/Sounds/Other/email_entact.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CryptoMarius/CryptoScanBot/6beada462008b1e92b5cf55fd764c70d8c70a604/CryptoScanBot.Core/Sounds/Other/email_entact.wav -------------------------------------------------------------------------------- /CryptoScanBot.Core/Sounds/Other/fade_in.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CryptoMarius/CryptoScanBot/6beada462008b1e92b5cf55fd764c70d8c70a604/CryptoScanBot.Core/Sounds/Other/fade_in.wav -------------------------------------------------------------------------------- /CryptoScanBot.Core/Sounds/Other/huawei.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CryptoMarius/CryptoScanBot/6beada462008b1e92b5cf55fd764c70d8c70a604/CryptoScanBot.Core/Sounds/Other/huawei.wav -------------------------------------------------------------------------------- /CryptoScanBot.Core/Sounds/Other/la_cucaracha.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CryptoMarius/CryptoScanBot/6beada462008b1e92b5cf55fd764c70d8c70a604/CryptoScanBot.Core/Sounds/Other/la_cucaracha.wav -------------------------------------------------------------------------------- /CryptoScanBot.Core/Sounds/Other/luana.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CryptoMarius/CryptoScanBot/6beada462008b1e92b5cf55fd764c70d8c70a604/CryptoScanBot.Core/Sounds/Other/luana.wav -------------------------------------------------------------------------------- /CryptoScanBot.Core/Sounds/Other/mind_transfer_no_jutsu.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CryptoMarius/CryptoScanBot/6beada462008b1e92b5cf55fd764c70d8c70a604/CryptoScanBot.Core/Sounds/Other/mind_transfer_no_jutsu.wav -------------------------------------------------------------------------------- /CryptoScanBot.Core/Sounds/Other/notification.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CryptoMarius/CryptoScanBot/6beada462008b1e92b5cf55fd764c70d8c70a604/CryptoScanBot.Core/Sounds/Other/notification.wav -------------------------------------------------------------------------------- /CryptoScanBot.Core/Sounds/Other/popup.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CryptoMarius/CryptoScanBot/6beada462008b1e92b5cf55fd764c70d8c70a604/CryptoScanBot.Core/Sounds/Other/popup.wav -------------------------------------------------------------------------------- /CryptoScanBot.Core/Sounds/Other/proxima.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CryptoMarius/CryptoScanBot/6beada462008b1e92b5cf55fd764c70d8c70a604/CryptoScanBot.Core/Sounds/Other/proxima.wav -------------------------------------------------------------------------------- /CryptoScanBot.Core/Sounds/Other/star_trek_energize.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CryptoMarius/CryptoScanBot/6beada462008b1e92b5cf55fd764c70d8c70a604/CryptoScanBot.Core/Sounds/Other/star_trek_energize.wav -------------------------------------------------------------------------------- /CryptoScanBot.Core/Sounds/Other/suffocation.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CryptoMarius/CryptoScanBot/6beada462008b1e92b5cf55fd764c70d8c70a604/CryptoScanBot.Core/Sounds/Other/suffocation.wav -------------------------------------------------------------------------------- /CryptoScanBot.Core/Sounds/Other/xiaomi_fress.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CryptoMarius/CryptoScanBot/6beada462008b1e92b5cf55fd764c70d8c70a604/CryptoScanBot.Core/Sounds/Other/xiaomi_fress.wav -------------------------------------------------------------------------------- /CryptoScanBot.Core/Sounds/sound-domnear-overbought.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CryptoMarius/CryptoScanBot/6beada462008b1e92b5cf55fd764c70d8c70a604/CryptoScanBot.Core/Sounds/sound-domnear-overbought.wav -------------------------------------------------------------------------------- /CryptoScanBot.Core/Sounds/sound-domnear-oversold.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CryptoMarius/CryptoScanBot/6beada462008b1e92b5cf55fd764c70d8c70a604/CryptoScanBot.Core/Sounds/sound-domnear-oversold.wav -------------------------------------------------------------------------------- /CryptoScanBot.Core/Sounds/sound-domnearby-overbought.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CryptoMarius/CryptoScanBot/6beada462008b1e92b5cf55fd764c70d8c70a604/CryptoScanBot.Core/Sounds/sound-domnearby-overbought.wav -------------------------------------------------------------------------------- /CryptoScanBot.Core/Sounds/sound-domnearby-oversold.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CryptoMarius/CryptoScanBot/6beada462008b1e92b5cf55fd764c70d8c70a604/CryptoScanBot.Core/Sounds/sound-domnearby-oversold.wav -------------------------------------------------------------------------------- /CryptoScanBot.Core/Sounds/sound-heartbeat.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CryptoMarius/CryptoScanBot/6beada462008b1e92b5cf55fd764c70d8c70a604/CryptoScanBot.Core/Sounds/sound-heartbeat.wav -------------------------------------------------------------------------------- /CryptoScanBot.Core/Sounds/sound-jump-down.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CryptoMarius/CryptoScanBot/6beada462008b1e92b5cf55fd764c70d8c70a604/CryptoScanBot.Core/Sounds/sound-jump-down.wav -------------------------------------------------------------------------------- /CryptoScanBot.Core/Sounds/sound-jump-up.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CryptoMarius/CryptoScanBot/6beada462008b1e92b5cf55fd764c70d8c70a604/CryptoScanBot.Core/Sounds/sound-jump-up.wav -------------------------------------------------------------------------------- /CryptoScanBot.Core/Sounds/sound-sbm-overbought2.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CryptoMarius/CryptoScanBot/6beada462008b1e92b5cf55fd764c70d8c70a604/CryptoScanBot.Core/Sounds/sound-sbm-overbought2.wav -------------------------------------------------------------------------------- /CryptoScanBot.Core/Sounds/sound-sbm-oversold2.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CryptoMarius/CryptoScanBot/6beada462008b1e92b5cf55fd764c70d8c70a604/CryptoScanBot.Core/Sounds/sound-sbm-oversold2.wav -------------------------------------------------------------------------------- /CryptoScanBot.Core/Sounds/sound-stobb-overbought.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CryptoMarius/CryptoScanBot/6beada462008b1e92b5cf55fd764c70d8c70a604/CryptoScanBot.Core/Sounds/sound-stobb-overbought.wav -------------------------------------------------------------------------------- /CryptoScanBot.Core/Sounds/sound-stobb-overbought2.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CryptoMarius/CryptoScanBot/6beada462008b1e92b5cf55fd764c70d8c70a604/CryptoScanBot.Core/Sounds/sound-stobb-overbought2.wav -------------------------------------------------------------------------------- /CryptoScanBot.Core/Sounds/sound-stobb-oversold.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CryptoMarius/CryptoScanBot/6beada462008b1e92b5cf55fd764c70d8c70a604/CryptoScanBot.Core/Sounds/sound-stobb-oversold.wav -------------------------------------------------------------------------------- /CryptoScanBot.Core/Sounds/sound-stobb-oversold2.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CryptoMarius/CryptoScanBot/6beada462008b1e92b5cf55fd764c70d8c70a604/CryptoScanBot.Core/Sounds/sound-stobb-oversold2.wav -------------------------------------------------------------------------------- /CryptoScanBot.Core/Sounds/sound-storsi-overbought.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CryptoMarius/CryptoScanBot/6beada462008b1e92b5cf55fd764c70d8c70a604/CryptoScanBot.Core/Sounds/sound-storsi-overbought.wav -------------------------------------------------------------------------------- /CryptoScanBot.Core/Sounds/sound-storsi-oversold.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CryptoMarius/CryptoScanBot/6beada462008b1e92b5cf55fd764c70d8c70a604/CryptoScanBot.Core/Sounds/sound-storsi-oversold.wav -------------------------------------------------------------------------------- /CryptoScanBot.Core/Sounds/sound-trade-notification.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CryptoMarius/CryptoScanBot/6beada462008b1e92b5cf55fd764c70d8c70a604/CryptoScanBot.Core/Sounds/sound-trade-notification.wav -------------------------------------------------------------------------------- /CryptoScanBot.Core/Sounds/sound-trade-notification2.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CryptoMarius/CryptoScanBot/6beada462008b1e92b5cf55fd764c70d8c70a604/CryptoScanBot.Core/Sounds/sound-trade-notification2.wav -------------------------------------------------------------------------------- /CryptoScanBot.Core/Sounds/sound-uuh-overbought.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CryptoMarius/CryptoScanBot/6beada462008b1e92b5cf55fd764c70d8c70a604/CryptoScanBot.Core/Sounds/sound-uuh-overbought.wav -------------------------------------------------------------------------------- /CryptoScanBot.Core/Sounds/sound-uuh-oversold.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CryptoMarius/CryptoScanBot/6beada462008b1e92b5cf55fd764c70d8c70a604/CryptoScanBot.Core/Sounds/sound-uuh-oversold.wav -------------------------------------------------------------------------------- /CryptoScanBot.Core/Telegram/TelegramCalculateZones.cs: -------------------------------------------------------------------------------- 1 | using CryptoScanBot.Core.Zones; 2 | 3 | using System.Text; 4 | 5 | namespace CryptoScanBot.Core.Telegram; 6 | 7 | public class TelegramCalculateZones 8 | { 9 | public static void Execute(string arguments, StringBuilder stringbuilder) 10 | { 11 | LiquidityZones.CalculateZonesForAllSymbolsAsync(null); 12 | stringbuilder.AppendLine("Started calculations of zones"); 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /CryptoScanBot.Core/Telegram/TelegramResetScanner.cs: -------------------------------------------------------------------------------- 1 | using CryptoScanBot.Core.Core; 2 | 3 | using System.Text; 4 | 5 | namespace CryptoScanBot.Core.Telegram; 6 | 7 | public class TelegramResetScanner 8 | { 9 | public static void Execute(string arguments, StringBuilder stringbuilder) 10 | { 11 | ScannerSession.ScheduleRefresh(); 12 | stringbuilder.AppendLine("Scheduled restart of the scanner"); 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /CryptoScanBot.Core/Telegram/TelegramShowBarometer.cs: -------------------------------------------------------------------------------- 1 | using CryptoScanBot.Core.Barometer; 2 | using CryptoScanBot.Core.Core; 3 | using CryptoScanBot.Core.Enums; 4 | using CryptoScanBot.Core.Model; 5 | 6 | using System.Text; 7 | 8 | namespace CryptoScanBot.Core.Telegram; 9 | public class TelegramShowBarometer 10 | { 11 | public static void ShowBarometer(string arguments, StringBuilder stringbuilder) 12 | { 13 | //string text = "\\\Bla /Bla , Bla, hello 'h'"; 14 | string quote = "USDT"; 15 | string[] parameters = arguments.Split(' '); 16 | if (parameters.Length > 1) 17 | quote = parameters[1].Trim().ToUpper(); 18 | 19 | stringbuilder.AppendLine(string.Format("Barometer {0}", quote)); 20 | 21 | // Even een quick fix voor de barometer 22 | if (GlobalData.Settings.QuoteCoins.TryGetValue(quote, out CryptoQuoteData? quoteData)) 23 | { 24 | for (CryptoIntervalPeriod intervalPeriod = CryptoIntervalPeriod.interval5m; intervalPeriod <= CryptoIntervalPeriod.interval1d; intervalPeriod++) 25 | { 26 | if (intervalPeriod == CryptoIntervalPeriod.interval5m || intervalPeriod == CryptoIntervalPeriod.interval15m || intervalPeriod == CryptoIntervalPeriod.interval30m || 27 | intervalPeriod == CryptoIntervalPeriod.interval1h || intervalPeriod == CryptoIntervalPeriod.interval4h || intervalPeriod == CryptoIntervalPeriod.interval1d) 28 | { 29 | BarometerData? barometerData = GlobalData.ActiveAccount!.Data.GetBarometer(quoteData.Name, intervalPeriod); 30 | stringbuilder.AppendLine(string.Format("{0} {1:N2}", intervalPeriod, barometerData.PriceBarometer)); 31 | } 32 | } 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /CryptoScanBot.Core/Telegram/TelegramShowHelp.cs: -------------------------------------------------------------------------------- 1 | using System.Text; 2 | 3 | namespace CryptoScanBot.Core.Telegram; 4 | 5 | public class TelegramShowHelp 6 | { 7 | public static void ShowHelp(StringBuilder stringBuilder) 8 | { 9 | stringBuilder.AppendLine("status show status bots"); 10 | 11 | stringBuilder.AppendLine("start start trade bot"); 12 | stringBuilder.AppendLine("stop stop trade bot"); 13 | stringBuilder.AppendLine("positions show positions trade bot"); 14 | stringBuilder.AppendLine("profits show profits trade bot (today)"); 15 | 16 | stringBuilder.AppendLine("signalstart start signal bot"); 17 | stringBuilder.AppendLine("signalstop stop signal bot"); 18 | stringBuilder.AppendLine("reset reset the scanner (restart)"); 19 | stringBuilder.AppendLine("calculatezones calculate the zones"); 20 | 21 | stringBuilder.AppendLine("value show value BTC,BNB and ETH"); // todo, de juiste basismunten tonen 22 | stringBuilder.AppendLine("barometer show barometer BTC/ETH/USDT"); // todo, de juiste basismunten tonen 23 | stringBuilder.AppendLine("assets show asset overview"); 24 | stringBuilder.AppendLine("chatid ChatId configuratie"); 25 | stringBuilder.AppendLine("help this help screen"); 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /CryptoScanBot.Core/Telegram/TelegramShowStatus.cs: -------------------------------------------------------------------------------- 1 | using CryptoScanBot.Core.Core; 2 | 3 | using System.Text; 4 | 5 | namespace CryptoScanBot.Core.Telegram; 6 | public class TelegramShowStatus 7 | { 8 | public static void ShowStatus(string arguments, StringBuilder stringbuilder) 9 | { 10 | if (arguments.Length != 1000) 11 | stringbuilder.AppendLine("not supported"); 12 | 13 | //Bot status 14 | if (GlobalData.Settings.Trading.Active) 15 | stringbuilder.AppendLine($"Trade bot is active! (slots long={GlobalData.Settings.Trading.SlotsMaximalLong}, slots short={GlobalData.Settings.Trading.SlotsMaximalShort})"); 16 | else 17 | stringbuilder.AppendLine("Trade bot is not active!"); 18 | 19 | 20 | // Create signals 21 | if (GlobalData.Settings.Signal.Active) 22 | stringbuilder.AppendLine("Signal bot is active!"); 23 | else 24 | stringbuilder.AppendLine("Signal bot is not active!"); 25 | 26 | //// Create sound 27 | //if (GlobalData.Settings.Signal.SoundSignalNotification) 28 | // stringbuilder.AppendLine("Signal sound is active!"); 29 | //else 30 | // stringbuilder.AppendLine("Signal sound is not active!"); 31 | 32 | // Trade sound 33 | if (GlobalData.Settings.General.SoundTradeNotification) 34 | stringbuilder.AppendLine("Trade sound is active!"); 35 | else 36 | stringbuilder.AppendLine("Trade sound is not active!"); 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /CryptoScanBot.Core/Telegram/TelegramShowTrend.cs: -------------------------------------------------------------------------------- 1 | using CryptoScanBot.Core.Account; 2 | using CryptoScanBot.Core.Core; 3 | using CryptoScanBot.Core.Enums; 4 | using CryptoScanBot.Core.Model; 5 | using CryptoScanBot.Core.Trend; 6 | 7 | using System.Text; 8 | 9 | namespace CryptoScanBot.Core.Telegram; 10 | 11 | public class TelegramShowTrend 12 | { 13 | public static async Task ShowTrendAsync(string arguments, StringBuilder stringbuilder) 14 | { 15 | string symbolName = ""; 16 | string[] parameters = arguments.Split(' '); 17 | if (parameters.Length > 1) 18 | symbolName = parameters[1].Trim().ToUpper(); 19 | stringbuilder.AppendLine($"Trend {symbolName}"); 20 | 21 | var exchange = GlobalData.Settings.General.Exchange; 22 | if (exchange != null) 23 | { 24 | if (exchange.SymbolListName.TryGetValue(symbolName, out CryptoSymbol? symbol)) 25 | { 26 | await MarketTrend.CalculateMarketTrendAsync(GlobalData.ActiveAccount!, symbol, 0, 0); 27 | 28 | AccountSymbolData accountSymbolData = GlobalData.ActiveAccount!.Data.GetSymbolData(symbol.Name); 29 | foreach (AccountSymbolIntervalData accountSymbolIntervalData in accountSymbolData.SymbolTrendDataList) 30 | { 31 | string s; 32 | if (accountSymbolIntervalData.TrendIndicator == CryptoTrendIndicator.Bullish) 33 | s = "trend=bullish"; 34 | else if (accountSymbolIntervalData.TrendIndicator == CryptoTrendIndicator.Bearish) 35 | s = "trend=bearish"; 36 | else 37 | s = "trend=sideway's?"; 38 | stringbuilder.AppendLine($"{accountSymbolIntervalData.Interval.Name} {s}"); 39 | } 40 | 41 | float marketTrend = (float)accountSymbolData.MarketTrendPercentage!; 42 | if (marketTrend < 0) 43 | stringbuilder.AppendLine($"Symbol trend {marketTrend:N2}% bearish"); 44 | else if (marketTrend > 0) 45 | stringbuilder.AppendLine($"Symbol trend {marketTrend:N2}% bullish"); 46 | else 47 | stringbuilder.AppendLine($"Symbol trend {marketTrend:N2}% unknown"); 48 | } 49 | } 50 | } 51 | 52 | } 53 | -------------------------------------------------------------------------------- /CryptoScanBot.Core/Telegram/TelegramShowValue.cs: -------------------------------------------------------------------------------- 1 | using CryptoScanBot.Core.Core; 2 | using CryptoScanBot.Core.Model; 3 | 4 | using System.Text; 5 | 6 | namespace CryptoScanBot.Core.Telegram; 7 | 8 | public class TelegramShowValue 9 | { 10 | public static void ShowValue(string arguments, StringBuilder stringbuilder) 11 | { 12 | //string value; 13 | //string[] parameters = arguments.Split(' '); 14 | //if (parameters.Length >= 2) 15 | // value = parameters[1]; 16 | //else 17 | // value = GlobalData.Settings.ShowSymbolInformation.ToList(); 18 | // //"BTCUSDT,ETHUSDT,PAXGUSDT,BNBUSDT"; 19 | //parameters = value.Split(','); 20 | var parameters = GlobalData.Settings.ShowSymbolInformation; 21 | 22 | var exchange = GlobalData.Settings.General.Exchange; 23 | if (exchange != null) 24 | { 25 | foreach (string symbolName in parameters) 26 | { 27 | if (exchange.SymbolListName.TryGetValue(symbolName + "USDT", out CryptoSymbol? symbol)) 28 | { 29 | if (symbol.LastPrice.HasValue) 30 | { 31 | string text = string.Format("{0} waarde {1:N2}", symbolName, (decimal)symbol.LastPrice); 32 | stringbuilder.AppendLine(text); 33 | } 34 | } 35 | 36 | } 37 | } 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /CryptoScanBot.Core/Trader/TradeHandler.cs: -------------------------------------------------------------------------------- 1 | using CryptoScanBot.Core.Core; 2 | using CryptoScanBot.Core.Enums; 3 | using CryptoScanBot.Core.Model; 4 | 5 | namespace CryptoScanBot.Core.Trader; 6 | 7 | public static class TradeHandler 8 | { 9 | /// 10 | /// Vanuit de user ticker komt een reactie op een trade. De positie wordt doorgegeven naar 11 | /// een andere thread waar de positie doorberekend wordt (met een kleine vertraging) 12 | /// NB: De meegegeven order is meestal een tijdelijke order (voor interne datatransfer) 13 | /// 14 | public static async Task HandleTradeAsync(CryptoSymbol symbol, CryptoOrderStatus orderStatus, CryptoOrder order) 15 | { 16 | // Find the open position 17 | if (order.TradeAccount.Data.PositionList.TryGetValue(symbol.Name, out CryptoPosition? position)) 18 | { 19 | // could also be done in ThreadDoubleCheckPosition 20 | if (!GlobalData.BackTest && orderStatus.IsFilled() && GlobalData.Settings.General.SoundTradeNotification) 21 | GlobalData.PlaySomeMusic("sound-trade-notification.wav"); 22 | 23 | // De actie doorgeven naar een andere thread 24 | position.ForceCheckPosition = true; 25 | position.DelayUntil = GlobalData.GetCurrentDateTime(position.Account).AddSeconds(10); 26 | if (GlobalData.ThreadCheckPosition != null) 27 | await GlobalData.ThreadCheckPosition.AddToQueue(position, order.OrderId, order.Status); 28 | 29 | // Moved to ThreadCheckPosition (we need the trades for the exact fees) 30 | //PaperAssets.Change(position.Account, position.Symbol, position.Side, order.Side, CryptoOrderStatus.Filled, order.Quantity, order.QuoteQuantity); 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /CryptoScanBot.Core/TradingView/TradingViewJsonParser.cs: -------------------------------------------------------------------------------- 1 | using CryptoScanBot.Core.Core; 2 | 3 | using System.Text.Json; 4 | 5 | namespace CryptoScanBot.Core.TradingView; 6 | 7 | public static class TradingViewJsonParser 8 | { 9 | public static JsonDocument? TryParse(string message) 10 | { 11 | try 12 | { 13 | if (!message.StartsWith("{\"m")) 14 | return null; 15 | 16 | JsonSerializerOptions options = new() { PropertyNameCaseInsensitive = true }; 17 | var root = JsonSerializer.Deserialize(message, options); 18 | var p = root?.P[1].ToString() ?? ""; 19 | if (root?.M != "qsd") 20 | return null; 21 | 22 | var branch = JsonSerializer.Deserialize(p, options); 23 | 24 | return JsonDocument.Parse(branch?.V?.ToString() ?? ""); 25 | } 26 | catch (Exception e) 27 | { 28 | ScannerLog.Logger.Error(e, ""); 29 | return null; 30 | } 31 | } 32 | 33 | } 34 | 35 | public class TradingViewJsonRootObject 36 | { 37 | public required string M { get; set; } 38 | public required List P { get; set; } 39 | } 40 | 41 | public class TradingViewJsonPayloadObject 42 | { 43 | public required string N { get; set; } 44 | public required string S { get; set; } 45 | public required object V { get; set; } 46 | } 47 | 48 | public class TradingViewMarketStatusObject 49 | { 50 | public required string Phase { get; set; } 51 | public required string Tradingday { get; set; } 52 | } 53 | -------------------------------------------------------------------------------- /CryptoScanBot.Core/Trend/ZigZagResult.cs: -------------------------------------------------------------------------------- 1 | using CryptoScanBot.Core.Model; 2 | 3 | namespace CryptoScanBot.Core.Trend; 4 | 5 | [Serializable] 6 | public class ZigZagResult 7 | { 8 | public required char PointType { get; set; } // indicates a specific point and type e.g. H or L 9 | public required decimal Value { get; set; } 10 | public required CryptoCandle Candle { get; set; } 11 | 12 | // Some call this Strong or Weak instead of Dominant, its the same concept 13 | public bool Dominant { get; set; } = false; 14 | public bool IsValid { get; set; } = false; 15 | public bool Dummy { get; set; } = false; 16 | public string NiceIntro { get; set; } = ""; // intro before box is interesting (a "jump" into the zone, ==not a small step) 17 | 18 | public decimal? BackupValue { get; set; } 19 | public CryptoCandle? BackupCandle { get; set; } 20 | public int? BackupIndex { get; set; } 21 | 22 | 23 | // Zone 24 | //public DateTime OpenTime { get; set; } 25 | public decimal Top { get; set; } 26 | public decimal Bottom { get; set; } 27 | public double Percentage { get; set; } 28 | public long? CloseDate { get; set; } 29 | 30 | public int PivotIndex { get; set; } 31 | 32 | public void ReusePoint(CryptoCandle candle, decimal value, bool dummy, int pivotIndex) 33 | { 34 | // Intention is to reset stuff because we are going to reuse a pivot point, clear the other stuff 35 | Value = value; 36 | Candle = candle; 37 | PivotIndex = pivotIndex; 38 | if (!dummy) 39 | Backup(); 40 | 41 | // Reset other stuff 42 | Dominant = false; 43 | Top = 0; 44 | Bottom = 0; 45 | Percentage = 0; 46 | CloseDate = null; 47 | } 48 | 49 | public void Backup() 50 | { 51 | BackupValue = Value; 52 | BackupCandle = Candle; 53 | BackupIndex = PivotIndex; 54 | } 55 | 56 | public void Restore() 57 | { 58 | if (BackupValue != null) 59 | Value = BackupValue.Value; 60 | if (BackupCandle != null) 61 | Candle = BackupCandle; 62 | if (BackupIndex != null) 63 | PivotIndex = BackupIndex.Value; 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /CryptoScanBot.Core/Zones/CryptoZoneData.cs: -------------------------------------------------------------------------------- 1 | using CryptoScanBot.Core.Model; 2 | using CryptoScanBot.Core.Trend; 3 | 4 | namespace CryptoScanBot.Core.Zones; 5 | 6 | public class CryptoZoneData 7 | { 8 | public required CryptoAccount Account { get; set; } 9 | public required Model.CryptoExchange Exchange { get; set; } 10 | public required CryptoSymbol Symbol { get; set; } 11 | public required CryptoInterval Interval { get; set; } 12 | public required CryptoSymbolInterval SymbolInterval { get; set; } 13 | 14 | // All zones from the database (including the closed) 15 | public List ZoneListLong { get; set; } = []; 16 | public List ZoneListShort { get; set; } = []; 17 | 18 | public required ZigZagIndicator9 Indicator { get; set; } 19 | public required ZigZagIndicator9 IndicatorFib { get; set; } 20 | 21 | public List Signals { get; set; } = []; 22 | //public List Positions { get; set; } = []; 23 | } -------------------------------------------------------------------------------- /CryptoScanBot.Core/Zones/ThreadZoneCalculate.cs: -------------------------------------------------------------------------------- 1 | using CryptoScanBot.Core.Core; 2 | using CryptoScanBot.Core.Model; 3 | 4 | using System.Collections.Concurrent; 5 | 6 | namespace CryptoScanBot.Core.Zones; 7 | 8 | public class ThreadZoneCalculate 9 | { 10 | 11 | private readonly BlockingCollection Queue = []; 12 | private readonly CancellationTokenSource cancellationToken = new(); 13 | 14 | 15 | public void Stop() 16 | { 17 | cancellationToken.Cancel(); 18 | //GlobalData.AddTextToLogTab(string.Format("Stop calculating zones")); 19 | } 20 | 21 | 22 | public void AddToQueue(CryptoSymbol symbol) 23 | { 24 | Queue.Add(symbol); 25 | } 26 | 27 | 28 | public async Task ExecuteAsync() 29 | { 30 | //GlobalData.AddTextToLogTab("Starting task for calculating zones"); 31 | try 32 | { 33 | foreach (CryptoSymbol symbol in Queue.GetConsumingEnumerable(cancellationToken.Token)) 34 | { 35 | await LiquidityZones.CalculateZones(null, symbol); 36 | //await MarketTrend.CalculateMarketTrendAsync(GlobalData.ActiveAccount!, symbol, 0, 0); 37 | } 38 | } 39 | catch (OperationCanceledException) 40 | { 41 | // niets.. 42 | } 43 | catch (Exception error) 44 | { 45 | ScannerLog.Logger.Error(error, ""); 46 | GlobalData.AddTextToLogTab($"ThreadZoneCalculate ERROR {error.Message}"); 47 | } 48 | 49 | GlobalData.AddTextToLogTab("ThreadZoneCalculate thread exit"); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /CryptoScanBot.CoreTests/CryptoScanBot.CoreTests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net8.0-windows 5 | latest 6 | enable 7 | enable 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | Always 28 | 29 | 30 | PreserveNewest 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /CryptoScanBot.CoreTests/Intern/IntervalToolsTests.cs: -------------------------------------------------------------------------------- 1 | using CryptoScanBot.Core.Core; 2 | using CryptoScanBot.Core.Enums; 3 | using CryptoScanBot.Core.Model; 4 | 5 | namespace CryptoScanBot.CoreTests.Intern; 6 | 7 | [TestClass()] 8 | public class IntervalToolsTests : TestBase 9 | { 10 | [TestMethod] 11 | public void StartOfIntervalCandle3Test1() 12 | { 13 | InitTestSession(); 14 | 15 | CryptoInterval intervalSource = GlobalData.IntervalListPeriod[CryptoIntervalPeriod.interval10m]; 16 | CryptoInterval intervalTarget = GlobalData.IntervalListPeriod[CryptoIntervalPeriod.interval1h]; 17 | 18 | DateTime now = new(2024, 12, 1, 0, 0, 0, 0, DateTimeKind.Utc); 19 | long sourceStart = CandleTools.GetUnixTime(now, intervalSource.Duration); 20 | 21 | for (int i = 0; i < 6; i++) 22 | { 23 | long sourceStartLoop = sourceStart + i * intervalSource.Duration; 24 | (bool targetComplete, long targetStart) = IntervalTools.StartOfIntervalCandle3(sourceStartLoop, intervalSource.Duration, intervalTarget.Duration); 25 | 26 | Assert.AreEqual(targetStart, sourceStart, "Target date"); 27 | Assert.AreEqual(targetComplete, i == 5, "Target complete"); 28 | } 29 | } 30 | 31 | 32 | [TestMethod] 33 | public void StartOfIntervalCandle3Test2() 34 | { 35 | // Same as the first test, but the startdate is shifted 5 minutes 36 | 37 | InitTestSession(); 38 | 39 | CryptoInterval intervalSource = GlobalData.IntervalListPeriod[CryptoIntervalPeriod.interval10m]; 40 | CryptoInterval intervalTarget = GlobalData.IntervalListPeriod[CryptoIntervalPeriod.interval1h]; 41 | 42 | DateTime now = new(2024, 12, 1, 0, 5, 0, 0, DateTimeKind.Utc); 43 | long sourceStart = CandleTools.GetUnixTime(now, intervalSource.Duration); 44 | 45 | for (int i = 0; i < 6; i++) 46 | { 47 | long sourceStartLoop = sourceStart + i * intervalSource.Duration; 48 | (bool targetIncomplete, long targetStart) = IntervalTools.StartOfIntervalCandle3(sourceStartLoop, intervalSource.Duration, intervalTarget.Duration); 49 | 50 | Assert.AreEqual(targetStart, sourceStart, "Target date"); 51 | Assert.AreEqual(targetIncomplete, i == 5, "Target complete"); 52 | } 53 | } 54 | } -------------------------------------------------------------------------------- /CryptoScanBot.CoreTests/Trend/ETHUSDT/Strange trend lines 1h.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CryptoMarius/CryptoScanBot/6beada462008b1e92b5cf55fd764c70d8c70a604/CryptoScanBot.CoreTests/Trend/ETHUSDT/Strange trend lines 1h.png -------------------------------------------------------------------------------- /CryptoScanBot.CoreTests/Trend/STETHUSDT/Strange trend lines 1h + indexes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CryptoMarius/CryptoScanBot/6beada462008b1e92b5cf55fd764c70d8c70a604/CryptoScanBot.CoreTests/Trend/STETHUSDT/Strange trend lines 1h + indexes.png -------------------------------------------------------------------------------- /CryptoScanBot.CoreTests/Trend/STETHUSDT/Strange trend lines 1h.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CryptoMarius/CryptoScanBot/6beada462008b1e92b5cf55fd764c70d8c70a604/CryptoScanBot.CoreTests/Trend/STETHUSDT/Strange trend lines 1h.png -------------------------------------------------------------------------------- /CryptoScanBot.ZoneVisualisation/CryptoScanBot.ZoneVisualisation.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Library 5 | net8.0-windows 6 | enable 7 | true 8 | enable 9 | 10 | 11 | 12 | False 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /CryptoScanBot.ZoneVisualisation/ExtraData.cs: -------------------------------------------------------------------------------- 1 | using CryptoScanBot.Core.Context; 2 | using CryptoScanBot.Core.Core; 3 | using CryptoScanBot.Core.Model; 4 | 5 | using Dapper; 6 | 7 | namespace CryptoScanBot.Core.Zones; 8 | 9 | public class ExtraData 10 | { 11 | 12 | public static void LoadSignalsForSymbol(CryptoZoneData data, long from) 13 | { 14 | data.Signals.Clear(); 15 | string sql = "select * from signal where BackTest=0 and SymbolId = @SymbolId and EventTime > @eventTime"; 16 | 17 | using var database = new CryptoDatabase(); 18 | try 19 | { 20 | foreach (CryptoSignal signal in database.Connection.Query(sql, new { SymbolId = data.Symbol.Id, eventTime = from })) 21 | { 22 | if (GlobalData.ExchangeListId.TryGetValue(signal.ExchangeId, out Model.CryptoExchange? exchange2)) 23 | { 24 | signal.Exchange = exchange2; 25 | 26 | if (exchange2.SymbolListId.TryGetValue(signal.SymbolId, out CryptoSymbol? symbol)) 27 | { 28 | signal.Symbol = symbol; 29 | 30 | if (GlobalData.IntervalListId.TryGetValue(signal.IntervalId, out CryptoInterval? interval)) 31 | signal.Interval = interval; 32 | 33 | data.Signals.Add(signal); 34 | } 35 | } 36 | } 37 | } 38 | finally 39 | { 40 | database.Close(); 41 | } 42 | 43 | 44 | } 45 | 46 | public static void LoadPositionsForSymbol(CryptoZoneData data, long from) 47 | { 48 | //data.Positions.Clear(); 49 | //using var database = new CryptoDatabase(); 50 | //string sql = "select * from position where TradeAccountId=@TradeAccountId and SymbolId = @SymbolId order by id desc limit 50"; 51 | //foreach (CryptoPosition position in database.Connection.Query(sql, new { TradeAccountId = GlobalData.ActiveAccount!.Id })) 52 | //{ 53 | // if (!GlobalData.TradeAccountList.TryGetValue(position.TradeAccountId, out CryptoAccount? tradeAccount)) 54 | // throw new Exception("No trading account found"); 55 | 56 | // data.Positions.Add(position); 57 | //} 58 | 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /CryptoScanBot/Commands/Command.cs: -------------------------------------------------------------------------------- 1 | namespace CryptoScanBot.Commands; 2 | 3 | public enum Command 4 | { 5 | None, 6 | ActivateTradingApp, 7 | ActivateActiveExchange, 8 | ActivateTradingviewIntern, 9 | ActivateTradingviewExtern, 10 | ShowTrendInformation, 11 | ExcelSignalInformation, 12 | ExcelSignalsInformation, 13 | ExcelSymbolInformation, 14 | ExcelExchangeInformation, 15 | ExcelPositionInformation, 16 | ExcelPositionsInformation, 17 | CopyDataGridCells, 18 | CopySymbolInformation, 19 | ScannerSessionDebug, 20 | PositionCalculate, 21 | TradingViewImportList, 22 | ShowSymbolGraph, 23 | About, 24 | CalculateAllLiquidityZones, 25 | CalculateSymbolLiquidityZones, 26 | } 27 | 28 | // Work in progres, opzetje tichting ICommand (teveel werk op dit moment) 29 | // De parameters zijn/worden aardig complex) -> eens nazoeken hoe en wat) 30 | 31 | public abstract class CommandBase 32 | { 33 | public abstract void Execute(ToolStripMenuItemCommand item, object sender); 34 | } 35 | -------------------------------------------------------------------------------- /CryptoScanBot/Commands/CommandAbout.cs: -------------------------------------------------------------------------------- 1 | namespace CryptoScanBot.Commands; 2 | 3 | public class CommandAbout : CommandBase 4 | { 5 | public override void Execute(ToolStripMenuItemCommand item, object sender) 6 | { 7 | AboutBox form = new() 8 | { 9 | StartPosition = FormStartPosition.CenterParent 10 | }; 11 | form.ShowDialog(); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /CryptoScanBot/Commands/CommandCopyDataCells.cs: -------------------------------------------------------------------------------- 1 | namespace CryptoScanBot.Commands; 2 | 3 | public class CommandCopyDataCells : CommandBase 4 | { 5 | public override void Execute(ToolStripMenuItemCommand item, object sender) 6 | { 7 | string text = ""; 8 | if (sender is CryptoDataGrid grid) 9 | { 10 | if (grid.Grid.SelectedRows.Count > 0) 11 | { 12 | int rowIndex = grid.Grid.SelectedRows[0].Index; 13 | 14 | for (int columnIndex = 0; columnIndex < grid.Grid.ColumnCount - 1; columnIndex++) 15 | { 16 | //var item = grid.Grid.Rows[rowIndex].Cells[columnIndex]; 17 | DataGridViewCellValueEventArgs e = new(columnIndex, rowIndex); 18 | grid.GetTextFunction(sender, e); 19 | text += e.Value?.ToString() + ";"; 20 | } 21 | text += "\r\n"; 22 | } 23 | } 24 | 25 | if (text == "") 26 | Clipboard.Clear(); 27 | else 28 | Clipboard.SetText(text, TextDataFormat.UnicodeText); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /CryptoScanBot/Commands/CommandCopySymbolInfo.cs: -------------------------------------------------------------------------------- 1 | using CryptoScanBot.Core.Model; 2 | 3 | namespace CryptoScanBot.Commands; 4 | 5 | public class CommandCopySymbolInfo : CommandBase 6 | { 7 | public override void Execute(ToolStripMenuItemCommand item, object sender) 8 | { 9 | string text = ""; 10 | if (sender is CryptoSymbol symbol) 11 | text = symbol.Name; 12 | 13 | if (text == "") 14 | Clipboard.Clear(); 15 | else 16 | Clipboard.SetText(text, TextDataFormat.UnicodeText); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /CryptoScanBot/Commands/CommandHelper.cs: -------------------------------------------------------------------------------- 1 | namespace CryptoScanBot.Commands; 2 | 3 | public static class CommandHelper 4 | { 5 | 6 | public static void AddSeperator(this ContextMenuStrip menuStrip) => menuStrip.Items.Add(new ToolStripSeparator()); 7 | 8 | public static void AddSeperator(this ToolStripMenuItem menuStrip) => menuStrip.DropDownItems.Add(new ToolStripSeparator()); 9 | 10 | public static ToolStripMenuItemCommand AddCommand(this ContextMenuStrip menuStrip, CryptoDataGrid? dataGrid, 11 | string text, Command command, EventHandler? click = null, Keys? shortcutKeys = null) 12 | { 13 | ToolStripMenuItemCommand menuItem = new() 14 | { 15 | Command = command, 16 | DataGrid = dataGrid, 17 | Text = text, 18 | }; 19 | if (shortcutKeys != null) 20 | menuItem.ShortcutKeys = shortcutKeys.Value; 21 | if (click == null) 22 | menuItem.Click += click ?? CommandTools.ExecuteCommand; 23 | else 24 | menuItem.Click += click; 25 | menuStrip.Items.Add(menuItem); 26 | return menuItem; 27 | } 28 | 29 | public static ToolStripMenuItemCommand AddCommand(this ToolStripMenuItem menuStrip, CryptoDataGrid? dataGrid, 30 | string text, Command command, EventHandler? click = null, Keys? shortcutKeys = null) 31 | { 32 | ToolStripMenuItemCommand menuItem = new() 33 | { 34 | Command = command, 35 | DataGrid = dataGrid, 36 | Text = text, 37 | }; 38 | if (shortcutKeys != null) 39 | menuItem.ShortcutKeys = shortcutKeys.Value; 40 | menuItem.Click += click ?? CommandTools.ExecuteCommand; 41 | menuStrip.DropDownItems.Add(menuItem); 42 | return menuItem; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /CryptoScanBot/Commands/CommandShowGraph.cs: -------------------------------------------------------------------------------- 1 | using CryptoScanBot.Core.Model; 2 | using CryptoScanBot.ZoneVisualisation; 3 | 4 | namespace CryptoScanBot.Commands; 5 | 6 | public class CommandShowGraph : CommandBase 7 | { 8 | private static CryptoVisualisation? CryptoVisualisationForm = null; 9 | 10 | public override void Execute(ToolStripMenuItemCommand item, object? sender) 11 | { 12 | if (sender != null) 13 | { 14 | CryptoVisualisation? dialog = null; 15 | try 16 | { 17 | if (CryptoVisualisationForm != null && !CryptoVisualisationForm.IsDisposed) 18 | dialog = CryptoVisualisationForm; 19 | } 20 | catch (ObjectDisposedException) 21 | { 22 | CryptoVisualisationForm = null; 23 | } 24 | 25 | dialog ??= new() 26 | { 27 | StartPosition = FormStartPosition.CenterParent 28 | }; 29 | 30 | dialog.StartWithSymbolAsync(sender); 31 | dialog.Show(); 32 | if (CryptoVisualisationForm != null) 33 | dialog.BringToFront(); 34 | 35 | CryptoVisualisationForm = dialog; 36 | } 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /CryptoScanBot/Commands/CommandTradingViewImportList.cs: -------------------------------------------------------------------------------- 1 | using CryptoScanBot.Core.Core; 2 | using CryptoScanBot.Core.Enums; 3 | using CryptoScanBot.Core.Model; 4 | 5 | using System.Diagnostics; 6 | using System.Text; 7 | 8 | namespace CryptoScanBot.Commands; 9 | 10 | public class CommandTradingViewImportList 11 | { 12 | /// 13 | /// Export all the sysmbol of the exchange to TV files 14 | /// 15 | public static void ExportList() 16 | { 17 | string folder = GlobalData.GetBaseDir() + $@"\TV-Import\"; 18 | Directory.CreateDirectory(folder); 19 | 20 | StringBuilder tvImportListAll = new(); 21 | foreach (CryptoQuoteData quoteData in GlobalData.Settings.QuoteCoins.Values) 22 | { 23 | StringBuilder tvImportList = new(); 24 | tvImportList.AppendLine($"###{quoteData.Name} MARKETS"); 25 | 26 | foreach (CryptoSymbol symbol in quoteData.SymbolList) 27 | { 28 | if (symbol.Status == 1 && !symbol.IsBarometerSymbol()) 29 | { 30 | // Parse the exchange code "BINANCE" or "BYBIT" + symbol and suffix.. 31 | //Url = "https://www.tradingview.com/chart/?symbol=BINANCE:{BASE}{QUOTE}&interval={interval}" 32 | (string url, _) = GlobalData.ExternalUrls.GetExternalRef(CryptoTradingApp.TradingView, false, symbol, GlobalData.IntervalList[0]); 33 | string[] subs = url.Split(new string[] { "symbol=", "&interval=" }, StringSplitOptions.None); 34 | if (subs.Length > 1) 35 | { 36 | tvImportList.AppendLine(subs[1]); 37 | tvImportListAll.AppendLine(subs[1]); 38 | } 39 | } 40 | } 41 | string filename = folder + $"TV import {quoteData.Name}.txt"; 42 | File.WriteAllText(filename, tvImportList.ToString()); 43 | } 44 | 45 | string filenameAll = folder + $"TV import ALL.txt"; 46 | File.WriteAllText(filenameAll, tvImportListAll.ToString()); 47 | 48 | GlobalData.AddTextToLogTab("Generated Tradingview import files"); 49 | Process.Start(new ProcessStartInfo(folder) { UseShellExecute = true }); 50 | } 51 | 52 | } 53 | -------------------------------------------------------------------------------- /CryptoScanBot/Commands/ToolStripMenuItemCommand.cs: -------------------------------------------------------------------------------- 1 | namespace CryptoScanBot.Commands; 2 | 3 | public class ToolStripMenuItemCommand : ToolStripMenuItem 4 | { 5 | public new Command Command { get; set; } 6 | public CryptoDataGrid? DataGrid { get; set; } 7 | } 8 | -------------------------------------------------------------------------------- /CryptoScanBot/CryptoDataGridColumns.cs: -------------------------------------------------------------------------------- 1 | using CryptoScanBot.Core.Settings; 2 | 3 | namespace CryptoScanBot; 4 | 5 | public partial class CryptoDataGridColumns : Form 6 | { 7 | public required CryptoDataGrid Grid; 8 | private readonly List List = []; 9 | 10 | public CryptoDataGridColumns() 11 | { 12 | InitializeComponent(); 13 | } 14 | 15 | 16 | public void AddColumns(CryptoDataGrid grid) 17 | { 18 | Grid = grid; 19 | 20 | foreach (DataGridViewColumn column in Grid.Grid.Columns) 21 | { 22 | if (!Grid.ColumnList.TryGetValue(column.HeaderText, out ColumnSetting? columnSetting)) 23 | { 24 | columnSetting = new(); 25 | if (column.Tag is bool alwaysVisible) 26 | columnSetting.AlwaysVisible = alwaysVisible; 27 | Grid.ColumnList.Add(column.HeaderText, columnSetting); 28 | } 29 | 30 | CheckBox item = new() 31 | { 32 | Tag = column, 33 | AutoSize = true, 34 | Text = column.HeaderText, 35 | Size = new Size(100, 22), 36 | CheckState = CheckState.Unchecked, 37 | Checked = columnSetting.Visible || columnSetting.AlwaysVisible, 38 | }; 39 | flowLayoutPanel.Controls.Add(item); 40 | List.Add(item); 41 | } 42 | } 43 | 44 | public void FormOkay() 45 | { 46 | foreach (var item in List) 47 | { 48 | if (!Grid.ColumnList.TryGetValue(item.Text, out ColumnSetting? columnSetting)) 49 | { 50 | columnSetting = new(); 51 | Grid.ColumnList.Add(item.Text, columnSetting); 52 | } 53 | columnSetting.Visible = item.Checked || columnSetting.AlwaysVisible; 54 | } 55 | } 56 | 57 | private void ButtonOkClick(object? sender, EventArgs? e) 58 | { 59 | FormOkay(); 60 | DialogResult = DialogResult.OK; 61 | } 62 | 63 | private void ButtonCancelClick(object? sender, EventArgs? e) 64 | { 65 | DialogResult = DialogResult.Cancel; 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /CryptoScanBot/Help/CryptoScanBot.docx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CryptoMarius/CryptoScanBot/6beada462008b1e92b5cf55fd764c70d8c70a604/CryptoScanBot/Help/CryptoScanBot.docx -------------------------------------------------------------------------------- /CryptoScanBot/Help/CryptoScanBot.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CryptoMarius/CryptoScanBot/6beada462008b1e92b5cf55fd764c70d8c70a604/CryptoScanBot/Help/CryptoScanBot.pdf -------------------------------------------------------------------------------- /CryptoScanBot/Help/Roadmap.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CryptoMarius/CryptoScanBot/6beada462008b1e92b5cf55fd764c70d8c70a604/CryptoScanBot/Help/Roadmap.txt -------------------------------------------------------------------------------- /CryptoScanBot/Intern/SpeechPlayer.cs: -------------------------------------------------------------------------------- 1 | using CryptoScanBot.Core.Core; 2 | 3 | using System.Collections.Concurrent; 4 | using System.Speech.Synthesis; 5 | 6 | namespace CryptoScanBot.Intern; 7 | 8 | public static class ThreadSpeechPlayer 9 | { 10 | private static Thread? speechPlayThread; 11 | private static readonly BlockingCollection speechQueue = []; 12 | private static readonly CancellationTokenSource speechCancelToken = new(); 13 | 14 | public static void AddToQueue(string filename) 15 | { 16 | speechQueue.Add(filename); 17 | StartSpeechThread(); 18 | } 19 | 20 | 21 | private static void StartSpeechThread() 22 | { 23 | //Sound Player Loop Thread 24 | if (speechPlayThread == null || !speechPlayThread.IsAlive) 25 | { 26 | speechPlayThread = new Thread(SpeechThreadExecute) 27 | { 28 | Name = "SpeechPlayer", 29 | IsBackground = true 30 | }; 31 | speechPlayThread.Start(); 32 | } 33 | } 34 | 35 | /// 36 | /// Method that the outside thread will use outside the thread of this class 37 | /// 38 | public static void SpeechThreadExecute() 39 | { 40 | try 41 | { 42 | using SpeechSynthesizer synthesizer = new(); 43 | // to change VoiceGender and VoiceAge check out those links below 44 | synthesizer.SelectVoiceByHints(VoiceGender.Male, VoiceAge.Adult); 45 | synthesizer.Volume = 100; // (0 - 100) 46 | synthesizer.Rate = 0; // (-10 - 10) 47 | 48 | foreach (string text in speechQueue.GetConsumingEnumerable(speechCancelToken.Token)) 49 | { 50 | synthesizer.Speak(text); 51 | } 52 | } 53 | catch (Exception error) 54 | { 55 | ScannerLog.Logger.Error(error, ""); 56 | GlobalData.AddTextToLogTab(""); 57 | GlobalData.AddTextToLogTab(error.ToString()); 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /CryptoScanBot/Intern/WebBrowser.cs: -------------------------------------------------------------------------------- 1 | using CryptoScanBot.Core.Core; 2 | 3 | using Microsoft.Web.WebView2.Core; 4 | 5 | namespace CryptoScanBot.Intern; 6 | 7 | 8 | public class WebBrowser 9 | { 10 | public bool BrowserInitialized { get; set; } 11 | public Microsoft.Web.WebView2.WinForms.WebView2? Browser { get; set; } 12 | 13 | public async Task InitializeBrowserAsync() 14 | { 15 | if (Browser != null && !BrowserInitialized) 16 | { 17 | BrowserInitialized = true; 18 | 19 | // https://stackoverflow.com/questions/63404822/how-to-disable-cors-in-wpf-webview2 20 | var userPath = GlobalData.GetBaseDir(); 21 | CoreWebView2Environment cwv2Environment = await CoreWebView2Environment.CreateAsync(null, userPath, new CoreWebView2EnvironmentOptions()); 22 | await Browser.EnsureCoreWebView2Async(cwv2Environment); 23 | } 24 | } 25 | 26 | public async Task ActivateUrlAsync(string url) 27 | { 28 | await InitializeBrowserAsync(); 29 | if (Browser != null) 30 | Browser.Source = new(url); 31 | } 32 | } 33 | 34 | -------------------------------------------------------------------------------- /CryptoScanBot/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.InteropServices; 3 | using System.Runtime.Versioning; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("CryptoScanBot")] 9 | [assembly: AssemblyDescription("STOBB, SBM, STORSI signal scanner")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("Marius")] 12 | [assembly: AssemblyProduct("CryptoScanBot")] 13 | [assembly: AssemblyCopyright("CryptoScanBot © 2024")] 14 | [assembly: AssemblyTrademark("https://t.me/+LiHJxgEUibg5YjE8")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("7e2bd970-0f4e-4d7d-aee5-619086170d32")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("2.0.1.0")] 36 | [assembly: AssemblyFileVersion("2.0.1.0")] 37 | 38 | [assembly: SupportedOSPlatform("windows")] -------------------------------------------------------------------------------- /CryptoScanBot/Properties/Settings.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.42000 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace CryptoScanBot.Properties { 12 | 13 | 14 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 15 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "17.9.0.0")] 16 | internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { 17 | 18 | private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); 19 | 20 | public static Settings Default { 21 | get { 22 | return defaultInstance; 23 | } 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /CryptoScanBot/Properties/Settings.settings: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /CryptoScanBot/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "profiles": { 3 | "CryptoScanBot": { 4 | "commandName": "Project", 5 | "commandLineArgs": "-e \"Bybit Spot\" -f \"CryptoScanBot\\CryptoScanBot 1.9.4\\Bybit Spot Alarm\"", 6 | "nativeDebugging": false 7 | } 8 | } 9 | } -------------------------------------------------------------------------------- /CryptoScanBot/Resources/ButtonOnOffGreen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CryptoMarius/CryptoScanBot/6beada462008b1e92b5cf55fd764c70d8c70a604/CryptoScanBot/Resources/ButtonOnOffGreen.png -------------------------------------------------------------------------------- /CryptoScanBot/Resources/ButtonOnOffRed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CryptoMarius/CryptoScanBot/6beada462008b1e92b5cf55fd764c70d8c70a604/CryptoScanBot/Resources/ButtonOnOffRed.png -------------------------------------------------------------------------------- /CryptoScanBot/Resources/icons.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CryptoMarius/CryptoScanBot/6beada462008b1e92b5cf55fd764c70d8c70a604/CryptoScanBot/Resources/icons.ico -------------------------------------------------------------------------------- /CryptoScanBot/Resources/logoPictureBox.Image.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CryptoMarius/CryptoScanBot/6beada462008b1e92b5cf55fd764c70d8c70a604/CryptoScanBot/Resources/logoPictureBox.Image.jpg -------------------------------------------------------------------------------- /CryptoScanBot/Resources/open-folder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CryptoMarius/CryptoScanBot/6beada462008b1e92b5cf55fd764c70d8c70a604/CryptoScanBot/Resources/open-folder.png -------------------------------------------------------------------------------- /CryptoScanBot/Resources/open-folder1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CryptoMarius/CryptoScanBot/6beada462008b1e92b5cf55fd764c70d8c70a604/CryptoScanBot/Resources/open-folder1.png -------------------------------------------------------------------------------- /CryptoScanBot/Resources/open-folderblack.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CryptoMarius/CryptoScanBot/6beada462008b1e92b5cf55fd764c70d8c70a604/CryptoScanBot/Resources/open-folderblack.png -------------------------------------------------------------------------------- /CryptoScanBot/Resources/volume.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CryptoMarius/CryptoScanBot/6beada462008b1e92b5cf55fd764c70d8c70a604/CryptoScanBot/Resources/volume.png -------------------------------------------------------------------------------- /CryptoScanBot/SettingsDialog/UserControlAltradyApi.cs: -------------------------------------------------------------------------------- 1 | using CryptoScanBot.Core.Settings; 2 | 3 | namespace CryptoScanBot.SettingsDialog; 4 | 5 | public partial class UserControlAltradyApi : UserControl 6 | { 7 | public UserControlAltradyApi() 8 | { 9 | InitializeComponent(); 10 | 11 | EditKey.TextChanged += EditApiKeyChanged; 12 | EditSecret.TextChanged += EditApiSecretChanged; 13 | } 14 | 15 | public void LoadConfig(SettingsAltradyApi settings) 16 | { 17 | EditKey.Text = settings.Key; 18 | EditSecret.Text = settings.Secret; 19 | 20 | EditApiKeyChanged(null, EventArgs.Empty); 21 | EditApiSecretChanged(null, EventArgs.Empty); 22 | } 23 | 24 | public void SaveConfig(SettingsAltradyApi settings) 25 | { 26 | settings.Key = EditKey.Text; 27 | settings.Secret = EditSecret.Text; 28 | } 29 | 30 | private static string GetDisplayApiKey(string text) 31 | { 32 | return text.Length < 4 ? "" : $"{text[..3]}.. {text[^3..]}"; 33 | } 34 | 35 | private void EditApiKeyChanged(object? sender, EventArgs e) 36 | { 37 | LabelApiKeyDisplay.Text = GetDisplayApiKey(EditKey.Text); 38 | } 39 | 40 | private void EditApiSecretChanged(object? sender, EventArgs e) 41 | { 42 | LabelApiSecretDisplay.Text = GetDisplayApiKey(EditSecret.Text); 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /CryptoScanBot/SettingsDialog/UserControlBarometer.cs: -------------------------------------------------------------------------------- 1 | using CryptoScanBot.Core.Settings; 2 | 3 | namespace CryptoScanBot.SettingsDialog; 4 | 5 | public partial class UserControlBarometer : UserControl 6 | { 7 | public UserControlBarometer() 8 | { 9 | InitializeComponent(); 10 | } 11 | 12 | public void LoadConfig(SettingsTextualBarometer settings) 13 | { 14 | UserControlBarometer15m.SetChecked("15m", settings.List); 15 | UserControlBarometer30m.SetChecked("30m", settings.List); 16 | UserControlBarometer1h.SetChecked("1h", settings.List); 17 | UserControlBarometer4h.SetChecked("4h", settings.List); 18 | UserControlBarometer1d.SetChecked("1d", settings.List); 19 | 20 | EditBarometerLog.Checked = settings.Log; 21 | } 22 | 23 | private static void GetChecked(string interval, UserControlBarometerInterval userControl, Dictionary barometer) 24 | { 25 | var value = userControl.GetChecked(); 26 | if (value.Checked) 27 | barometer.Add(interval, value.Item2); 28 | } 29 | 30 | public void SaveConfig(SettingsTextualBarometer settings) 31 | { 32 | settings.List.Clear(); 33 | GetChecked("15m", UserControlBarometer15m, settings.List); 34 | GetChecked("30m", UserControlBarometer30m, settings.List); 35 | GetChecked("1h", UserControlBarometer1h, settings.List); 36 | GetChecked("4h", UserControlBarometer4h, settings.List); 37 | GetChecked("1d", UserControlBarometer1d, settings.List); 38 | 39 | settings.Log = EditBarometerLog.Checked; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /CryptoScanBot/SettingsDialog/UserControlBarometerInterval.cs: -------------------------------------------------------------------------------- 1 | namespace CryptoScanBot.SettingsDialog; 2 | 3 | public partial class UserControlBarometerInterval : UserControl 4 | { 5 | public UserControlBarometerInterval() 6 | { 7 | InitializeComponent(); 8 | 9 | EditIsActive.Click += EditIsActiveChecked; 10 | } 11 | 12 | private void EditIsActiveChecked(object? sender, EventArgs? e) 13 | { 14 | EditMinimal.Enabled = EditIsActive.Checked; 15 | EditMaximal.Enabled = EditIsActive.Checked; 16 | } 17 | 18 | public void SetChecked(string interval, Dictionary barometer) 19 | { 20 | EditIsActive.Text = interval; 21 | 22 | EditMinimal.Minimum = -999; 23 | EditMinimal.Maximum = +999; 24 | 25 | EditMaximal.Minimum = -999; 26 | EditMaximal.Maximum = +999; 27 | 28 | if (barometer.TryGetValue(interval, out var value)) 29 | { 30 | EditIsActive.Checked = true; 31 | EditMinimal.Value = value.minValue; 32 | EditMaximal.Value = value.maxValue; 33 | } 34 | else 35 | { 36 | EditIsActive.Checked = false; 37 | EditMinimal.Value = -999; 38 | EditMaximal.Value = 999; 39 | } 40 | EditIsActiveChecked(null, null); 41 | } 42 | 43 | public (bool Checked, (decimal minValue, decimal maxValue)) GetChecked() 44 | { 45 | if (EditMinimal.Value > EditMaximal.Value) 46 | return (EditIsActive.Checked, (EditMaximal.Value, EditMinimal.Value)); 47 | else 48 | return (EditIsActive.Checked, (EditMinimal.Value, EditMaximal.Value)); 49 | } 50 | 51 | } 52 | -------------------------------------------------------------------------------- /CryptoScanBot/SettingsDialog/UserControlEverything.cs: -------------------------------------------------------------------------------- 1 | using CryptoScanBot.Core.Enums; 2 | using CryptoScanBot.Core.Settings; 3 | 4 | namespace CryptoScanBot.SettingsDialog; 5 | 6 | public partial class UserControlEverything : UserControl 7 | { 8 | public UserControlEverything() 9 | { 10 | InitializeComponent(); 11 | } 12 | 13 | public void InitControls(bool isForTrading, CryptoTradeSide side) 14 | { 15 | // Trading long/short (initialize list etc) 16 | UserControlStrategy.InitControls(isForTrading, side); 17 | UserControlInterval.InitControls(); 18 | UserControlIntervalTrend.InitControls(side); 19 | } 20 | 21 | public void LoadConfig(SettingsTextual settings) 22 | { 23 | UserControlStrategy.LoadConfig(settings.Strategy); 24 | UserControlIntervalTrend.LoadConfig(settings.IntervalTrend); 25 | UserControlInterval.LoadConfig(settings.Interval); 26 | UserControlBarometer.LoadConfig(settings.Barometer); 27 | UserControlMarketTrend.LoadConfig(settings.MarketTrend); 28 | } 29 | 30 | public void SaveConfig(SettingsTextual settings) 31 | { 32 | UserControlStrategy.SaveConfig(settings.Strategy); 33 | UserControlIntervalTrend.SaveConfig(settings.IntervalTrend); 34 | UserControlInterval.SaveConfig(settings.Interval); 35 | UserControlBarometer.SaveConfig(settings.Barometer); 36 | UserControlMarketTrend.SaveConfig(settings.MarketTrend); 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /CryptoScanBot/SettingsDialog/UserControlExchangeApi.cs: -------------------------------------------------------------------------------- 1 | using CryptoScanBot.Core.Settings; 2 | 3 | namespace CryptoScanBot.SettingsDialog; 4 | 5 | public partial class UserControlExchangeApi : UserControl 6 | { 7 | public UserControlExchangeApi() 8 | { 9 | InitializeComponent(); 10 | EditApiKey.TextChanged += EditApiKeyChanged; 11 | EditApiSecret.TextChanged += EditApiSecretChanged; 12 | } 13 | 14 | public void LoadConfig(SettingsExchangeApi settings) 15 | { 16 | EditApiKey.Text = settings.Key; 17 | EditApiSecret.Text = settings.Secret; 18 | 19 | EditApiKeyChanged(null, EventArgs.Empty); 20 | EditApiSecretChanged(null, EventArgs.Empty); 21 | } 22 | 23 | public void SaveConfig(SettingsExchangeApi settings) 24 | { 25 | settings.Key = EditApiKey.Text; 26 | settings.Secret = EditApiSecret.Text; 27 | } 28 | 29 | private static string GetDisplayApiKey(string text) 30 | { 31 | return text.Length < 4 ? "" : $"{text[..3]}.. {text[^3..]}"; 32 | } 33 | 34 | private void EditApiKeyChanged(object? sender, EventArgs e) 35 | { 36 | LabelApiKeyDisplay.Text = GetDisplayApiKey(EditApiKey.Text); 37 | } 38 | 39 | private void EditApiSecretChanged(object? sender, EventArgs e) 40 | { 41 | LabelApiSecretDisplay.Text = GetDisplayApiKey(EditApiSecret.Text); 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /CryptoScanBot/SettingsDialog/UserControlInterval.cs: -------------------------------------------------------------------------------- 1 | using CryptoScanBot.Core.Core; 2 | 3 | namespace CryptoScanBot.SettingsDialog; 4 | 5 | public partial class UserControlInterval : UserControl 6 | { 7 | 8 | // Gewenste trend op interval 9 | private readonly Dictionary ControlList = new(); 10 | 11 | public UserControlInterval() 12 | { 13 | InitializeComponent(); 14 | } 15 | 16 | public void InitControls() 17 | { 18 | foreach (var interval in GlobalData.IntervalList) 19 | { 20 | CheckBox checkbox = new() 21 | { 22 | AutoSize = true, 23 | UseVisualStyleBackColor = true, 24 | Text = interval.Name, 25 | }; 26 | flowLayoutPanel1.Controls.Add(checkbox); 27 | ControlList.Add(checkbox, interval.Name); 28 | } 29 | } 30 | 31 | public void LoadConfig(List settings) 32 | { 33 | foreach (var item in ControlList) 34 | item.Key.Checked = settings.Contains(item.Value); 35 | } 36 | 37 | public void SaveConfig(List settings) 38 | { 39 | settings.Clear(); 40 | foreach (var item in ControlList) 41 | { 42 | if (item.Key.Checked) 43 | settings.Add(item.Value); 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /CryptoScanBot/SettingsDialog/UserControlMarketTrend.cs: -------------------------------------------------------------------------------- 1 | using CryptoScanBot.Core.Settings; 2 | 3 | namespace CryptoScanBot.SettingsDialog; 4 | 5 | public partial class UserControlMarketTrend : UserControl 6 | { 7 | public UserControlMarketTrend() 8 | { 9 | InitializeComponent(); 10 | } 11 | 12 | public void LoadConfig(SettingsTextualMarketTrend settings) 13 | { 14 | EditLog.Checked = settings.Log; 15 | 16 | if (settings.List.Any()) 17 | UserControlTrendRange.SetChecked("Trend", true, (settings.List[0])); 18 | else 19 | UserControlTrendRange.SetChecked("Trend", false, (-100, 100)); 20 | } 21 | 22 | public void SaveConfig(SettingsTextualMarketTrend settings) 23 | { 24 | settings.List.Clear(); 25 | var (isActive, range) = UserControlTrendRange.GetChecked(); 26 | if (isActive) 27 | settings.List.Add(range); 28 | settings.Log = EditLog.Checked; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /CryptoScanBot/SettingsDialog/UserControlMarketTrendRange.cs: -------------------------------------------------------------------------------- 1 | namespace CryptoScanBot.SettingsDialog; 2 | 3 | public partial class UserControlMarketTrendRange : UserControl 4 | { 5 | public UserControlMarketTrendRange() 6 | { 7 | InitializeComponent(); 8 | 9 | EditIsActive.Click += EditIsActiveChecked; 10 | } 11 | 12 | private void EditIsActiveChecked(object? sender, EventArgs? e) 13 | { 14 | EditMinimal.Enabled = EditIsActive.Checked; 15 | EditMaximal.Enabled = EditIsActive.Checked; 16 | } 17 | 18 | public void SetChecked(string caption, bool isActive, (decimal minValue, decimal maxValue) range) 19 | { 20 | EditIsActive.Text = caption; 21 | 22 | EditMinimal.Minimum = -100; 23 | EditMinimal.Maximum = +100; 24 | 25 | EditMaximal.Minimum = -100; 26 | EditMaximal.Maximum = +100; 27 | 28 | if (isActive) 29 | { 30 | EditIsActive.Checked = isActive; 31 | EditMinimal.Value = range.minValue; 32 | EditMaximal.Value = range.maxValue; 33 | } 34 | else 35 | { 36 | EditIsActive.Checked = false; 37 | EditMinimal.Value = -100; 38 | EditMaximal.Value = 100; 39 | } 40 | EditIsActiveChecked(null, null); 41 | } 42 | 43 | public (bool isActive, (decimal minValue, decimal maxValue) range) GetChecked() 44 | { 45 | if (EditMinimal.Value > EditMaximal.Value) 46 | return (EditIsActive.Checked, (EditMaximal.Value, EditMinimal.Value)); 47 | else 48 | return (EditIsActive.Checked, (EditMinimal.Value, EditMaximal.Value)); 49 | } 50 | 51 | } 52 | -------------------------------------------------------------------------------- /CryptoScanBot/SettingsDialog/UserControlQuote.cs: -------------------------------------------------------------------------------- 1 | using CryptoScanBot.Core.Core; 2 | using CryptoScanBot.Core.Model; 3 | 4 | namespace CryptoScanBot.SettingsDialog; 5 | public partial class UserControlQuote : UserControl 6 | { 7 | 8 | public CryptoQuoteData QuoteData; 9 | 10 | public UserControlQuote() 11 | { 12 | InitializeComponent(); 13 | 14 | EditMinimumVolume.Maximum = decimal.MaxValue; 15 | EditMinimumPrice.Maximum = decimal.MaxValue; 16 | EditEntryAmount.Maximum = decimal.MaxValue; 17 | EditEntryPercentage.Maximum = 100; 18 | } 19 | 20 | public void LoadConfig(CryptoQuoteData quoteData) 21 | { 22 | QuoteData = quoteData; 23 | 24 | EditQuoteName.Text = quoteData.Name; 25 | EditQuoteName.Checked = quoteData.FetchCandles; 26 | EditMinimumVolume.Value = quoteData.MinimalVolume; 27 | EditMinimumPrice.Value = quoteData.MinimalPrice; 28 | PanelColor.BackColor = quoteData.DisplayColor; 29 | EditEntryAmount.Value = quoteData.EntryAmount; 30 | EditEntryPercentage.Value = quoteData.EntryPercentage; 31 | labelSymbols.Text = $"{quoteData.SymbolList.Count} symbols"; 32 | } 33 | 34 | public void SaveConfig(CryptoQuoteData quoteData) 35 | { 36 | quoteData.FetchCandles = EditQuoteName.Checked; 37 | quoteData.MinimalVolume = EditMinimumVolume.Value; 38 | quoteData.MinimalPrice = EditMinimumPrice.Value; 39 | quoteData.DisplayColor = PanelColor.BackColor; 40 | quoteData.EntryAmount = EditEntryAmount.Value; 41 | quoteData.EntryPercentage = EditEntryPercentage.Value; 42 | } 43 | 44 | private void ButtonColor_Click(object? sender, EventArgs e) 45 | { 46 | ColorDialog dlg = new() 47 | { 48 | Color = PanelColor.BackColor, 49 | CustomColors = GlobalData.SettingsUser.CustomColors 50 | }; 51 | if (dlg.ShowDialog() == DialogResult.OK) 52 | { 53 | PanelColor.BackColor = dlg.Color; 54 | GlobalData.SettingsUser.CustomColors = dlg.CustomColors; 55 | } 56 | } 57 | 58 | private void PanelColor_DoubleClick(object? sender, EventArgs e) 59 | { 60 | ButtonColor_Click(sender, e); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /CryptoScanBot/SettingsDialog/UserControlQuoteHeader.cs: -------------------------------------------------------------------------------- 1 | namespace CryptoScanBot.SettingsDialog; 2 | public partial class UserControlQuoteHeader : UserControl 3 | { 4 | public UserControlQuoteHeader() 5 | { 6 | InitializeComponent(); 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /CryptoScanBot/SettingsDialog/UserControlSettingsPlaySoundAndColors.cs: -------------------------------------------------------------------------------- 1 | using CryptoScanBot.Core.Settings.Strategy; 2 | 3 | namespace CryptoScanBot.SettingsDialog; 4 | 5 | public partial class UserControlSettingsPlaySoundAndColors : UserControl 6 | { 7 | public UserControlSettingsPlaySoundAndColors() 8 | { 9 | InitializeComponent(); 10 | } 11 | 12 | public void LoadConfig(string caption, SettingsSignalStrategyBase settings) 13 | { 14 | EditPlaySound.Checked = settings.PlaySound; 15 | EditPlaySpeech.Checked = settings.PlaySpeech; 16 | 17 | UserControlLong.LoadConfig(caption + " long", settings.ColorLong, settings.SoundFileLong); 18 | UserControlShort.LoadConfig(caption + " short", settings.ColorShort, settings.SoundFileShort); 19 | } 20 | 21 | public void SaveConfig(SettingsSignalStrategyBase settings) 22 | { 23 | settings.PlaySound = EditPlaySound.Checked; 24 | settings.PlaySpeech = EditPlaySpeech.Checked; 25 | 26 | settings.ColorLong = UserControlLong.GetColor(); 27 | settings.SoundFileLong = UserControlLong.GetSoundFile(); 28 | settings.ColorShort = UserControlShort.GetColor(); 29 | settings.SoundFileShort = UserControlShort.GetSoundFile(); 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /CryptoScanBot/SettingsDialog/UserControlStrategy.cs: -------------------------------------------------------------------------------- 1 | using CryptoScanBot.Core.Enums; 2 | using CryptoScanBot.Core.Signal; 3 | 4 | namespace CryptoScanBot.SettingsDialog; 5 | public partial class UserControlStrategy : UserControl 6 | { 7 | 8 | private readonly Dictionary ControlList = new(); 9 | 10 | public UserControlStrategy() 11 | { 12 | InitializeComponent(); 13 | } 14 | 15 | public void InitControls(bool isForTrading, CryptoTradeSide tradeSide) 16 | { 17 | foreach (var signalDefinition in RegisterAlgorithms.AlgorithmDefinitionList.Values) 18 | { 19 | if (signalDefinition.Strategy >= CryptoSignalStrategy.DominantLevel) 20 | continue; 21 | if (isForTrading && signalDefinition.Strategy == CryptoSignalStrategy.Jump) 22 | continue; 23 | 24 | bool validStrategy = ((tradeSide == CryptoTradeSide.Long && signalDefinition.AnalyzeLongType != null) || 25 | (tradeSide == CryptoTradeSide.Short && signalDefinition.AnalyzeShortType != null)); 26 | 27 | CheckBox checkbox = new() 28 | { 29 | AutoSize = true, 30 | UseVisualStyleBackColor = true, 31 | Text = RegisterAlgorithms.GetAlgorithm(signalDefinition.Strategy), 32 | }; 33 | flowLayoutPanel1.Controls.Add(checkbox); 34 | 35 | if (validStrategy) 36 | ControlList.Add(checkbox, checkbox.Text); 37 | else 38 | checkbox.Enabled = false; 39 | } 40 | } 41 | 42 | public void LoadConfig(List list) 43 | { 44 | foreach (var item in ControlList) 45 | item.Key.Checked = list.Contains(item.Value); 46 | } 47 | 48 | public void SaveConfig(List list) 49 | { 50 | list.Clear(); 51 | foreach (var item in ControlList) 52 | { 53 | if (item.Key.Checked) 54 | list.Add(item.Value); 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /CryptoScanBot/SettingsDialog/UserControlTelegram.cs: -------------------------------------------------------------------------------- 1 | using CryptoScanBot.Core.Core; 2 | using CryptoScanBot.Core.Telegram; 3 | 4 | namespace CryptoScanBot.SettingsDialog; 5 | 6 | public partial class UserControlTelegram : UserControl 7 | { 8 | public UserControlTelegram() 9 | { 10 | InitializeComponent(); 11 | 12 | EditTelegramToken.TextChanged += EditTokenChanged; 13 | EditTelegramChatId.TextChanged += EditChatIdChanged; 14 | 15 | ButtonTestTelegram.Click += ButtonTestTelegram_Click; 16 | buttonTelegramStart.Click += ButtonTelegramStart_Click; 17 | } 18 | 19 | private async void ButtonTelegramStart_Click(object? sender, EventArgs? e) 20 | { 21 | await ThreadTelegramBot.Start(EditTelegramToken.Text, EditTelegramChatId.Text); 22 | } 23 | 24 | private void ButtonTestTelegram_Click(object? sender, EventArgs? e) 25 | { 26 | ThreadTelegramBot.ChatId = EditTelegramChatId.Text; 27 | GlobalData.AddTextToTelegram("Dit is een test bericht"); 28 | } 29 | 30 | public void LoadConfig() 31 | { 32 | EditTelegramToken.Text = GlobalData.Telegram.Token; 33 | EditTelegramChatId.Text = GlobalData.Telegram.ChatId; 34 | EditUseEmojiInTrend.Checked = GlobalData.Telegram.EmojiInTrend; 35 | EditSendSignalsToTelegram.Checked = GlobalData.Telegram.SendSignalsToTelegram; 36 | 37 | EditTokenChanged(null, EventArgs.Empty); 38 | EditChatIdChanged(null, EventArgs.Empty); 39 | } 40 | 41 | public void SaveConfig() 42 | { 43 | GlobalData.Telegram.Token = EditTelegramToken.Text.Trim(); 44 | GlobalData.Telegram.ChatId = EditTelegramChatId.Text.Trim(); 45 | GlobalData.Telegram.EmojiInTrend = EditUseEmojiInTrend.Checked; 46 | GlobalData.Telegram.SendSignalsToTelegram = EditSendSignalsToTelegram.Checked; 47 | } 48 | 49 | private static string GetDisplayApiKey(string text) 50 | { 51 | return text.Length < 4 ? "" : $"{text[..3]}.. {text[^3..]}"; 52 | } 53 | 54 | private void EditTokenChanged(object? sender, EventArgs e) 55 | { 56 | LabelTelegramToken.Text = GetDisplayApiKey(EditTelegramToken.Text); 57 | } 58 | 59 | private void EditChatIdChanged(object? sender, EventArgs e) 60 | { 61 | LabelTelegramChatId.Text = GetDisplayApiKey(EditTelegramChatId.Text); 62 | } 63 | 64 | } 65 | -------------------------------------------------------------------------------- /CryptoScanBot/SettingsDialog/UserControlTradeDcaItem.cs: -------------------------------------------------------------------------------- 1 | using CryptoScanBot.Core.Settings; 2 | 3 | namespace CryptoScanBot.SettingsDialog; 4 | 5 | public partial class UserControlTradeDcaItem : UserControl 6 | { 7 | public UserControlTradeDcaItem() 8 | { 9 | InitializeComponent(); 10 | } 11 | 12 | public void LoadConfig(CryptoDcaEntry dca, int dcaIndex) 13 | { 14 | groupBoxDca.Text = $"DCA {dcaIndex}"; 15 | EditPercent.Value = dca.Percentage; 16 | EditFactor.Value = dca.Factor; 17 | } 18 | 19 | public void SaveConfig(CryptoDcaEntry dca) 20 | { 21 | dca.Percentage = EditPercent.Value; 22 | dca.Factor = EditFactor.Value; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /CryptoScanBot/SettingsDialog/UserControlTradeRuleItem.cs: -------------------------------------------------------------------------------- 1 | using CryptoScanBot.Core.Core; 2 | using CryptoScanBot.Core.Enums; 3 | 4 | namespace CryptoScanBot.SettingsDialog; 5 | 6 | public partial class UserControlTradeRuleItem : UserControl 7 | { 8 | private readonly SortedList IntervalList = new(); 9 | 10 | public UserControlTradeRuleItem() 11 | { 12 | InitializeComponent(); 13 | } 14 | 15 | public void LoadConfig(Core.Settings.PauseTradingRule item, int index) 16 | { 17 | if (EditInterval.DataSource == null) 18 | { 19 | foreach (var interval in GlobalData.IntervalList) 20 | IntervalList.Add(interval.Name, interval.IntervalPeriod); 21 | 22 | EditInterval.DataSource = new BindingSource(IntervalList, null); 23 | EditInterval.DisplayMember = "Key"; 24 | EditInterval.ValueMember = "Value"; 25 | } 26 | 27 | 28 | groupBoxDca.Text = $"Trading rule {index}"; 29 | 30 | EditSymbol.Text = item.Symbol; 31 | EditInterval.SelectedValue = item.Interval; 32 | EditPercent.Value = (decimal)item.Percentage; 33 | EditCandles.Value = item.Candles; 34 | EditCoolDown.Value = item.CoolDown; 35 | } 36 | 37 | public void SaveConfig(Core.Settings.PauseTradingRule item) 38 | { 39 | item.Symbol = EditSymbol.Text; 40 | item.Percentage = (double)EditPercent.Value; 41 | item.Candles = (int)EditCandles.Value; 42 | item.Interval = (CryptoIntervalPeriod)EditInterval.SelectedValue; 43 | item.CoolDown = (int)EditCoolDown.Value; 44 | } 45 | 46 | 47 | } 48 | -------------------------------------------------------------------------------- /CryptoScanBot/SettingsDialog/UserControlTradeStopLoss.cs: -------------------------------------------------------------------------------- 1 | using CryptoScanBot.Core.Settings; 2 | 3 | namespace CryptoScanBot.SettingsDialog; 4 | 5 | public partial class UserControlTradeStopLoss : UserControl 6 | { 7 | public UserControlTradeStopLoss() 8 | { 9 | InitializeComponent(); 10 | //EditUseStopLoss.Click += UseStopLossClicked; 11 | } 12 | 13 | public void LoadConfig(SettingsTrading settings) 14 | { 15 | //EditUseStopLoss.Checked = settings.UseStopLoss; 16 | EditStopPercentage.Value = settings.StopLossPercentage; 17 | EditStopLimitPercentage.Value = settings.StopLossLimitPercentage; 18 | 19 | //UseStopLossClicked(null, null); 20 | } 21 | 22 | public void SaveConfig(SettingsTrading settings) 23 | { 24 | //settings.UseStopLoss = EditUseStopLoss.Checked; 25 | settings.StopLossPercentage = EditStopPercentage.Value; 26 | settings.StopLossLimitPercentage = EditStopLimitPercentage.Value; 27 | } 28 | 29 | //private void UseStopLossClicked(object? sender, EventArgs? e) 30 | //{ 31 | // LabelStopPercentage.Enabled = EditUseStopLoss.Checked; 32 | // EditStopPercentage.Enabled = EditUseStopLoss.Checked; 33 | // LabelStopLimitPercentage.Enabled = EditUseStopLoss.Checked; 34 | // EditStopLimitPercentage.Enabled = EditUseStopLoss.Checked; 35 | //} 36 | 37 | } 38 | -------------------------------------------------------------------------------- /CryptoScanBot/SettingsDialog/UserControlTrendInterval.cs: -------------------------------------------------------------------------------- 1 | using CryptoScanBot.Core.Core; 2 | using CryptoScanBot.Core.Enums; 3 | using CryptoScanBot.Core.Settings; 4 | 5 | namespace CryptoScanBot.SettingsDialog; 6 | 7 | public partial class UserControlTrendInterval : UserControl 8 | { 9 | 10 | // Gewenste trend op interval 11 | private readonly Dictionary ControlList = new(); 12 | 13 | public UserControlTrendInterval() 14 | { 15 | InitializeComponent(); 16 | } 17 | 18 | public void InitControls(CryptoTradeSide side) 19 | { 20 | string text; 21 | if (side == CryptoTradeSide.Long) 22 | text = "bullish"; 23 | else 24 | text = "bearish"; 25 | 26 | foreach (var interval in GlobalData.IntervalList) 27 | { 28 | CheckBox checkbox = new() 29 | { 30 | AutoSize = true, 31 | UseVisualStyleBackColor = true, 32 | Text = interval.Name + " interval=" + text, 33 | }; 34 | flowLayoutPanel1.Controls.Add(checkbox); 35 | ControlList.Add(checkbox, interval.Name); 36 | } 37 | } 38 | 39 | public void LoadConfig(SettingsTextualIntervalTrend settings) 40 | { 41 | foreach (var item in ControlList) 42 | item.Key.Checked = settings.List.Contains(item.Value); 43 | } 44 | 45 | public void SaveConfig(SettingsTextualIntervalTrend settings) 46 | { 47 | settings.List.Clear(); 48 | foreach (var item in ControlList) 49 | { 50 | if (item.Key.Checked) 51 | settings.List.Add(item.Value); 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /CryptoScanBot/WinFormTools.cs: -------------------------------------------------------------------------------- 1 | using CryptoScanBot.Commands; 2 | using CryptoScanBot.Core.Core; 3 | using CryptoScanBot.Core.Enums; 4 | using CryptoScanBot.Core.Settings; 5 | 6 | using System.Collections; 7 | using System.Runtime.InteropServices; 8 | 9 | namespace CryptoScanBot; 10 | 11 | // Virtual DataGrid Base for displaying objects (symbol, signal, positions) 12 | 13 | public static class WinFormTools 14 | { 15 | 16 | [DllImport("user32.dll")] 17 | static extern IntPtr WindowFromPoint(POINT Point); 18 | 19 | [StructLayout(LayoutKind.Sequential)] 20 | public struct POINT 21 | { 22 | public int X; 23 | public int Y; 24 | 25 | public POINT(int x, int y) 26 | { 27 | this.X = x; 28 | this.Y = y; 29 | } 30 | 31 | public static implicit operator System.Drawing.Point(POINT p) 32 | { 33 | return new System.Drawing.Point(p.X, p.Y); 34 | } 35 | 36 | public static implicit operator POINT(System.Drawing.Point p) 37 | { 38 | return new POINT(p.X, p.Y); 39 | } 40 | } 41 | 42 | public static bool IsControlVisibleToUser(this Control control) 43 | { 44 | var pos = control.PointToScreen(control.Location); 45 | var pointsToCheck = new POINT[] 46 | { 47 | pos, 48 | new Point(pos.X + control.Width - 1, pos.Y), 49 | new Point(pos.X, pos.Y + control.Height - 1), 50 | new Point(pos.X + control.Width - 1, pos.Y + control.Height - 1), 51 | new Point(pos.X + control.Width/2, pos.Y + control.Height/2) 52 | }; 53 | 54 | foreach (var p in pointsToCheck) 55 | { 56 | var hwnd = WindowFromPoint(p); 57 | var other = Control.FromChildHandle(hwnd); 58 | if (other == null) 59 | continue; 60 | 61 | if (control == other || control.Contains(other)) 62 | return true; 63 | } 64 | 65 | return false; 66 | } 67 | } -------------------------------------------------------------------------------- /CryptoScanner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CryptoMarius/CryptoScanBot/6beada462008b1e92b5cf55fd764c70d8c70a604/CryptoScanner.png -------------------------------------------------------------------------------- /CryptoShowTrend/CryptoShowTrend.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | WinExe 5 | net8.0-windows 6 | enable 7 | true 8 | enable 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | Form 24 | 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /CryptoShowTrend/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "profiles": { 3 | "CryptoShowTrend": { 4 | "commandName": "Project", 5 | "commandLineArgs": "-e \"Bybit Spot\" -f \"CryptoScanBot\\CryptoScanBot 1.9.4\\Bybit Spot Test\"" 6 | } 7 | } 8 | } -------------------------------------------------------------------------------- /ExchangeTest/Exchange/Bybit/SpotUta/Test.cs: -------------------------------------------------------------------------------- 1 | using Bybit.Net.Clients; 2 | 3 | using CryptoExchange.Net.Authentication; 4 | 5 | using CryptoScanBot.Core.Core; 6 | 7 | namespace ExchangeTest.Exchange.Bybit.SpotUta; 8 | internal class Test 9 | { 10 | 11 | public static async void ByBitUtaSpotTestAsync() 12 | { 13 | GlobalData.LoadSettings(); 14 | 15 | BybitRestClient.SetDefaultOptions(options => 16 | { 17 | options.OutputOriginalData = true; 18 | options.SpotOptions.AutoTimestamp = true; 19 | options.ReceiveWindow = TimeSpan.FromSeconds(15); 20 | if (GlobalData.TradingApi.Key != "") 21 | options.ApiCredentials = new ApiCredentials(GlobalData.TradingApi.Key, GlobalData.TradingApi.Secret); 22 | }); 23 | 24 | BybitSocketClient.SetDefaultOptions(options => 25 | { 26 | //options.AutoReconnect = true; 27 | options.OutputOriginalData = true; 28 | options.ReconnectInterval = TimeSpan.FromSeconds(15); 29 | if (GlobalData.TradingApi.Key != "") 30 | options.ApiCredentials = new ApiCredentials(GlobalData.TradingApi.Key, GlobalData.TradingApi.Secret); 31 | }); 32 | 33 | 34 | //string symbolName = "SUSHIUSDTM"; 35 | //await CryptoScanBot.Kucoin.Futures.Symbols.GetSymbolsAsync(); 36 | //await ExchangeTest.Exchange.Bybit.SpotUta.Candles.GetSymbolsAsync(symbolName); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /ExchangeTest/ExchangeTest.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | WinExe 5 | net8.0-windows10.0.19041.0 6 | enable 7 | true 8 | enable 9 | 7.0 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /ExchangeTest/Program.cs: -------------------------------------------------------------------------------- 1 | using CryptoScanBot.Core.Core; 2 | 3 | using System.Reflection; 4 | 5 | namespace CryptoScanBot.Experiment; 6 | 7 | internal static class Program 8 | { 9 | /// 10 | /// The main entry point for the application. 11 | /// 12 | [STAThread] 13 | static void Main() 14 | { 15 | // Vroeger dan alle andere.. 16 | InitializeApplicationVariables(); 17 | ScannerLog.InitializeLogging(); 18 | 19 | // To customize application configuration such as set high DPI settings or default font, 20 | // see https://aka.ms/applicationconfiguration. 21 | ApplicationConfiguration.Initialize(); 22 | Application.Run(new Form1()); 23 | } 24 | 25 | 26 | public static void InitializeApplicationVariables() 27 | { 28 | // Appname && name of database 29 | GlobalData.AppName = "CryptoScanBot"; // Assembly.GetExecutingAssembly().GetName().Name; 30 | 31 | // Path of the executable 32 | GlobalData.AppPath = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location); 33 | 34 | // Version stuff 35 | var assembly = Assembly.GetExecutingAssembly().GetName(); 36 | string appVersion = assembly.Version.ToString(); 37 | while (appVersion.EndsWith(".0.0")) 38 | appVersion = appVersion[0..^2]; 39 | GlobalData.AppVersion = appVersion; 40 | } 41 | } -------------------------------------------------------------------------------- /ExchangeTest/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "profiles": { 3 | "ExchangeTest": { 4 | "commandName": "Project", 5 | "commandLineArgs": "-e \"Bybit Spot\" -f \"CryptoScanBot\\CryptoScanBot 1.9.3\\Bybit Spot Altrady\"" 6 | } 7 | } 8 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | CryptoScanBot for Binance Spot, Binance Futures, Bybit Spot, ByBit Futures, Kucoin Spot and Mexc Spot 2 | 3 | The Crypto scanner was initially only intended to generate oversold signals on the Binance exchange (because someone said something about DYOR and you shouldn't say that to a programmer). In the meantime, the application has been overhauled a number of times, split, merged the best points, improved, simplified, adapted for SBM signals and made multi-exchange. 4 | 5 | The purpose of this application is to generate 3 types of signals (STOBB, SBM and JUMP). These signals can be used to enter the crypto market on predetermined conditions. With all these signals, only certain conditions have occurred, always validate the market and currency conditions before you get in anything. In particular, the PSAR is calculated differently by TradinView and the SBM lines always have to be interpreted by a human. 6 | 7 | In latest editions we also try to show dominant zones and FVG *see chart form). 8 | 9 | The application currently supports Binance and Bybit spot and Futures. Kucoin is still under investigation but is currently plagued by technical issues. The application is built in a mix of English and Dutch, because a number of tools have been combined (please indicate whether any texts are disturbing and/or should be adjusted), so apologies in advance for English crypto terms, for an explanation you have to be on the internet or ask in a crypto group what it means (but always do your own research first). 10 | 11 | Furthermore: Very nice that you try this application, below is an explanation of what the application does, the installation, necessary settings and so on. I hope you enjoy trading, the communities and so on. Good luck in this special world! 12 | 13 | ![CryptoMarius_CryptoScanBot](https://github.com/user-attachments/assets/1509b67c-6891-4d32-9a4b-e6cdebd61022) 14 | ![HBARUSDT chart form](https://github.com/user-attachments/assets/6e94d55e-309d-4f93-a6ff-1c226227306e) 15 | 16 | You can find the installation/start quide in the document (Dutch only) 17 | -------------------------------------------------------------------------------- /Testjes/BackTest/BackTestData.cs: -------------------------------------------------------------------------------- 1 | using CryptoSbmScanner.Model; 2 | 3 | namespace CryptoSbmScanner.BackTest; 4 | 5 | ///// 6 | ///// Persistent data voor een symbol (op een bepaald interval), signaal (van een interval) of een positie (die net start)? 7 | ///// 8 | //public class BackTestData 9 | //{ 10 | // // Trading or Emulator 11 | // public int OrderId = 0; 12 | // public int DcaIndex = 0; 13 | // public int BuyTimeOut = 0; 14 | 15 | // // lijkt me overbodig omdat het nu vanuit een posutie wordt beredeneerd 16 | // public CryptoPosition Position; 17 | 18 | // // De laatste prijs waarop (bij)gekocht werd 19 | // public decimal LastBuyPrice; 20 | 21 | // public decimal PriceLastOversold; // De laagste prijs van een oversold 22 | 23 | // //public void Reset() 24 | // //{ 25 | // // // Trading or Emulator 26 | // // OrderId = 0; 27 | // // DcaIndex = 0; 28 | // // BuyTimeOut = 0; 29 | 30 | // // Position = null; 31 | // //} 32 | //} -------------------------------------------------------------------------------- /Testjes/CryptoScanBotTestjes.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | WinExe 5 | net8.0-windows10.0.19041.0 6 | true 7 | enable 8 | $(MSBuildProjectName) 9 | enable 10 | 11 | 12 | 13 | $(DefineConstants) 14 | 15 | 16 | 17 | $(DefineConstants) 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | TestForm.cs 39 | 40 | 41 | 42 | 43 | 44 | TestForm.cs 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /Testjes/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "profiles": { 3 | "CryptoSbmTestjes": { 4 | "commandName": "Project", 5 | "commandLineArgs": "-e \"Bybit Spot\" -f \"CryptoScanBot\\CryptoScanBot 1.9.4\\Bybit Spot Test\"" 6 | } 7 | } 8 | } -------------------------------------------------------------------------------- /Tradedash Sounds/01_Tradedash - Notification.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CryptoMarius/CryptoScanBot/6beada462008b1e92b5cf55fd764c70d8c70a604/Tradedash Sounds/01_Tradedash - Notification.mp3 -------------------------------------------------------------------------------- /Tradedash Sounds/02_Tradedash - Notification.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CryptoMarius/CryptoScanBot/6beada462008b1e92b5cf55fd764c70d8c70a604/Tradedash Sounds/02_Tradedash - Notification.wav -------------------------------------------------------------------------------- /Tradedash Sounds/03_Tradedash - More alert.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CryptoMarius/CryptoScanBot/6beada462008b1e92b5cf55fd764c70d8c70a604/Tradedash Sounds/03_Tradedash - More alert.mp3 -------------------------------------------------------------------------------- /Tradedash Sounds/04_Tradedash - More alert.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CryptoMarius/CryptoScanBot/6beada462008b1e92b5cf55fd764c70d8c70a604/Tradedash Sounds/04_Tradedash - More alert.wav -------------------------------------------------------------------------------- /Tradedash Sounds/05_Tradedash - Less alert.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CryptoMarius/CryptoScanBot/6beada462008b1e92b5cf55fd764c70d8c70a604/Tradedash Sounds/05_Tradedash - Less alert.wav -------------------------------------------------------------------------------- /Tradedash Sounds/06_Tradedash - Less alert.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CryptoMarius/CryptoScanBot/6beada462008b1e92b5cf55fd764c70d8c70a604/Tradedash Sounds/06_Tradedash - Less alert.mp3 -------------------------------------------------------------------------------- /testEnvironments.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "1", 3 | "environments": [ 4 | // See https://aka.ms/remotetesting for more details 5 | // about how to configure remote environments. 6 | //{ 7 | // "name": "WSL Ubuntu", 8 | // "type": "wsl", 9 | // "wslDistribution": "Ubuntu" 10 | //}, 11 | //{ 12 | // "name": "Docker dotnet/sdk", 13 | // "type": "docker", 14 | // "dockerImage": "mcr.microsoft.com/dotnet/sdk" 15 | //} 16 | ] 17 | } --------------------------------------------------------------------------------