从山证v2.3.0拷贝

This commit is contained in:
吴方海
2024-05-09 14:06:26 +08:00
parent 566ff33259
commit f9d8a256a6
4471 changed files with 1203456 additions and 9 deletions
@@ -0,0 +1,65 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using YLErp.BLL.Eod;
using YLErp.Cache;
using YLErp;
using YLErp.Helpers;
namespace RealTimeCalcPositionService
{
public class BondCalcKafkTask : IHostedService, IDisposable
{
private readonly IYcLogger _logger;
private KafkaConsumerHelper _rspCalcBondTopicConsumer;
private string onRspCalcBondTopic = string.Empty;
private string onRspCalcBondTopicGroupId = string.Empty;
private readonly CancellationTokenSource _cts = new CancellationTokenSource();
public BondCalcKafkTask()
{
_logger = LogFactory.GetLogger("BondCalcKafkTask");
onRspCalcBondTopic = Environment.GetEnvironmentVariable("KafkaConfig_OnRspCalcBondTopic");
onRspCalcBondTopicGroupId = Environment.GetEnvironmentVariable("KafkaConfig_OnRspCalcBondTopicGroupId");
_rspCalcBondTopicConsumer = new KafkaConsumerHelper(onRspCalcBondTopicGroupId, onRspCalcBondTopic);
}
public void Dispose()
{
_cts.Dispose();
}
public Task StartAsync(CancellationToken cancellationToken)
{
_logger.Info("ClientBalanceTask task is starting.");
Task.Run(() => ExecuteTask(_cts.Token), _cts.Token);
return Task.CompletedTask;
}
public async Task StopAsync(CancellationToken cancellationToken)
{
_logger.Info("ClientBalanceTask task is stopping.");
_cts.Cancel();
await Task.CompletedTask;
}
private void ExecuteTask(CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)
{
try
{
RealtimePnlCalc.ConsumerBondCalcResp(_rspCalcBondTopicConsumer);
}
catch (Exception ex)
{
_logger.Error(ex, "收益率接收计算结果服务异常:" + ex.Message);
}
}
}
}
}
@@ -0,0 +1,93 @@
using BaseOUDAL;
using DocumentFormat.OpenXml.Drawing.Charts;
using Newtonsoft.Json;
using Org.BouncyCastle.Ocsp;
using StackExchange.Redis;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Xml.Linq;
using YLErp;
using YLErp.Abstract;
using YLErp.BLL;
using YLErp.BLL.Eod;
using YLErp.Cache;
using YLErp.Helpers;
using YLErp.Model;
using YLErp.Modules;
using YLErp.Modules.ClientModule;
namespace RealTimeCalcPositionService
{
public class ClientNoDMABalanceTask : IHostedService, IDisposable
{
private readonly IYcLogger _logger;
private readonly CancellationTokenSource _cts = new CancellationTokenSource();
private IYLCache _yLCache;
public ClientNoDMABalanceTask(IYLCache yLCache)
{
_logger = LogFactory.GetLogger("ClientNoDMABalanceTask");
_yLCache= yLCache;
}
public void Dispose()
{
_cts.Dispose();
}
public Task StartAsync(CancellationToken cancellationToken)
{
_logger.Info("ClientNoDMABalanceTask task is starting.");
Task.Run(() => ExecuteTask(_cts.Token), _cts.Token);
return Task.CompletedTask;
}
private void ExecuteTask(CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)
{
try
{
using var clientDb = new ClientDBContext();
var clients= clientDb.client.Where(x=>x.SwapTradeType==0).ToList();
//系统交易日
var valuedate = valuedateBLL.ValueDate;
//获取根据系统时间
var lastBalanceDate = EodOperationBase.GetLastSettlementDate(valuedate);
foreach (var client in clients)
{
var cb = ClientAssetDataService.GetClientLatestBalance(null, lastBalanceDate, client.id, false, false, false);
cb.AvailableAmount = cb.AmountFund + cb.TotalCredit + cb.PayableMargin + cb.GuaranteesTotalAmount;
var obj = new ClientBalanceForTrsResponse
{
TotalAmountTotal = cb.RoundedTotalAmountTotal,
AvailableAmount = Math.Round(cb.AvailableAmount, 2),
PositionPv = cb.RoundedPositionPv,
PositionPnl = cb.RoundedPositionPnl,
DaliyPnl = Math.Round(cb.DaliyPnl, 2),
ClientId = client.id,
ClientType = cb.ClientType,
Credit = cb.TotalCredit
};
if (_yLCache != null)
{
_yLCache.StringSet<ClientBalanceForTrsResponse>("ClientBalance:" + cb.ClientId, obj);
}
}
Thread.Sleep(3000);
}
catch (Exception ex)
{
_logger.Error(ex, "普通实时客户资金服务异常:" + ex.Message);
}
}
}
public async Task StopAsync(CancellationToken cancellationToken)
{
_logger.Info("ClientNoDMABalanceTask task is stopping.");
_cts.Cancel();
await Task.CompletedTask;
}
}
}
@@ -0,0 +1,69 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using YLErp.Abstract;
using YLErp.BLL.Eod;
using YLErp.Cache;
using YLErp;
using Microsoft.Extensions.Caching.Memory;
namespace RealTimeCalcPositionService
{
public class ClientPosiTask : IHostedService, IDisposable
{
private readonly IYcLogger _logger;
private IYLCache _yLCache;
private readonly CancellationTokenSource _cts = new CancellationTokenSource();
private IKafkaProduce kafkaProduceHelper;
IMemoryCache memoryCache;
public ClientPosiTask(IYLCache yLCache, IKafkaProduce kafkaProduce)
{
_logger = LogFactory.GetLogger("Worker");
_yLCache = yLCache;
kafkaProduceHelper = kafkaProduce;
memoryCache = new MemoryCache(new MemoryCacheOptions());
RealtimePnlCalc.InitCache(_yLCache);
RealtimePnlCalc.InitKafka(kafkaProduceHelper);
}
public Task StartAsync(CancellationToken cancellationToken)
{
_logger.Info($"实时持仓服务开始:{DateTimeOffset.Now}");
Task.Run(() => ExecuteTask(_cts.Token), _cts.Token);
return Task.CompletedTask;
}
private void ExecuteTask(CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)
{
string calctime = memoryCache.Get<string>("calctime");
var currentTime = DateTime.Now;
bool hasNew= RealtimePnlCalc.HasNewFlow(currentTime);
if (string.IsNullOrEmpty(calctime)|| hasNew)
{
memoryCache.Set("calctime", currentTime.ToString("yyyy-MM-dd HH:mm:ss.fff"), TimeSpan.FromSeconds(30));
try
{
RealtimePnlCalc.RealtimeSwapPosition(new OptUserInfo(0, "互换实时持仓服务", OptUserFrom.Service));
}
catch (Exception ex)
{
_logger.Error(ex, "实时持仓服务异常:" + ex.Message);
}
}
}
}
public async Task StopAsync(CancellationToken cancellationToken)
{
_logger.Info($"实时持仓服务停止: {DateTimeOffset.Now}");
_cts.Cancel();
await Task.CompletedTask;
}
public void Dispose()
{
_cts.Dispose();
}
}
}
@@ -0,0 +1,121 @@
using DocumentFormat.OpenXml.Drawing.Charts;
using Newtonsoft.Json;
using Org.BouncyCastle.Ocsp;
using StackExchange.Redis;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Xml.Linq;
using YLErp;
using YLErp.Abstract;
using YLErp.BLL.Eod;
using YLErp.Cache;
using YLErp.Helpers;
using YLErp.Model;
using YLErp.Modules;
using YLErp.Modules.ClientModule;
namespace RealTimeCalcPositionService
{
public class ClientRealBalanceTask : IHostedService, IDisposable
{
private readonly IYcLogger _logger;
private IKafkaProduce kafkaProduceHelper;
private string onRspAccountCapitalTopicTopic = string.Empty;
private readonly CancellationTokenSource _cts = new CancellationTokenSource();
private Dictionary<int,string> clientDic=new Dictionary<int, string>();
private IYLCache _yLCache;
public ClientRealBalanceTask(IKafkaProduce kafkaProduce, IYLCache yLCache)
{
_logger = LogFactory.GetLogger("ClientRealBalanceTask");
onRspAccountCapitalTopicTopic = Environment.GetEnvironmentVariable("KafkaConfig_OnRspAccountCapitalTopic");
kafkaProduceHelper = kafkaProduce;
_yLCache= yLCache;
}
public void Dispose()
{
_cts.Dispose();
}
public Task StartAsync(CancellationToken cancellationToken)
{
_logger.Info("ClientBalanceTask task is starting.");
Task.Run(() => ExecuteTask(_cts.Token), _cts.Token);
return Task.CompletedTask;
}
private void ExecuteTask(CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)
{
try
{
var clientSettles = new RealTimeClientBanlanceService(new OptUserInfo(0, "实时客户资金服务", OptUserFrom.Service)).GetDMABalances();
foreach (var cb in clientSettles)
{
cb.AvailableAmount = cb.AmountFund + cb.TotalCredit + cb.PayableMargin + cb.GuaranteesTotalAmount;
Result result = new Result();
try
{
var obj = new ClientBalanceForTrsResponse
{
TotalAmountTotal = cb.RoundedTotalAmount,
AvailableAmount = Math.Round(cb.AvailableAmount, 2),
PositionPv = cb.RoundedPositionPv,
PositionPnl = cb.RoundedPositionPnl,
DaliyPnl = Math.Round(cb.DaliyPnl, 2),
ClientId = cb.ClientId,
ClientType = cb.ClientType,
Credit=cb.TotalCredit
};
result.success = true;
result.obj = obj;
if (_yLCache!=null)
{
_yLCache.StringSet<ClientBalanceForTrsResponse>("ClientBalance:"+ cb.ClientId,obj);
}
}
catch (Exception ex)
{
result.msg = ex.Message;
result.success = false;
}
string resultStr = JsonConvert.SerializeObject(result);
string newEncryStr= DataProtectHelper.Encrypt(resultStr);
bool needProduce= false;
if (clientDic.TryGetValue(cb.ClientId,out string encryStr))
{
if (encryStr!= newEncryStr)
{
needProduce = true;
clientDic[cb.ClientId]= newEncryStr;
}
}
else
{
clientDic.Add(cb.ClientId, newEncryStr);
needProduce = true;
}
if (needProduce)
{
kafkaProduceHelper.Produce(onRspAccountCapitalTopicTopic, resultStr);
}
}
Thread.Sleep(3000);
}
catch (Exception ex)
{
_logger.Error(ex, "实时客户资金服务异常:" + ex.Message);
}
}
}
public async Task StopAsync(CancellationToken cancellationToken)
{
_logger.Info("ClientBalanceTask task is stopping.");
_cts.Cancel();
await Task.CompletedTask;
}
}
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,34 @@
<?xml version="1.0" encoding="utf-8" ?>
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.nlog-project.org/schemas/NLog.xsd NLog.xsd"
autoReload="true"
throwExceptions="false"
internalLogLevel="Off" internalLogFile="c:\nlog\internal.log">
<targets>
<!---10M的信息日志文件-->
<target xsi:type="File" name="file" fileName="${basedir}/log/${shortdate}.log"
layout="${longdate}|${logger}|${uppercase:${level}}|${message};${exception:format=Message}" encoding="utf-8" archiveAboveSize="10485760" maxArchiveFiles="30" concurrentWrites="false" />
<!---10M的错误日志文件-->
<target xsi:type="File" name="file_error" fileName="${basedir}/log/${shortdate}.error.log"
layout="${longdate}|${logger}|${uppercase:${level}}|${message};${exception:format=ToString:innerFormat=ToString:maxInnerExceptionLevel=3}" encoding="utf-8" archiveAboveSize="10485760" maxArchiveFiles="60" concurrentWrites="false" />
<!---Console日志-->
<target name="console" xsi:type="Console" layout="${longdate}|${logger}|${uppercase:${level}}|${message};${exception:format=Message}" />
<!---调试日志文件-->
<target xsi:type="File" name="file_debug" fileName="${basedir}/log/debug_${shortdate}.log"
layout="${longdate}|${logger}|${uppercase:${level}}|${message};${exception:format=Message}" encoding="utf-8" archiveAboveSize="10485760" maxArchiveFiles="30" concurrentWrites="false" />
</targets>
<rules>
<logger name="*" minlevel="Info" writeTo="file" />
<logger name="*" minlevel="Error" writeTo="file_error" />
<logger name="*" minlevel="Debug" writeTo="console" />
<logger name="CalcDebug" minlevel="Debug" writeTo="file_debug" />
</rules>
</nlog>
@@ -0,0 +1,82 @@
using FluentFTP.Helpers;
using NLog.Web;
using RealTimeCalcPositionService;
using YieldChain.Commons;
using YLErp;
using YLErp.Abstract;
using YLErp.Helpers;
using YLErp.Model;
internal class Program
{
private static async Task Main(string[] args)
{
var host = Host.CreateDefaultBuilder(args)
.ConfigureAppConfiguration((ctx, cfgBuilder) =>
{
var config = cfgBuilder.Build();
var vpath = config.GetSection("AppSettings").GetValue<string>("VirtualPathRoot");
OtcAppContext.Initialize(new InnerServer(vpath).MapPath);
})
.ConfigureServices((hostContext, services) =>
{
YLServiceLocator.SetServiceCollection(services);
var appConfig = hostContext.Configuration;
services.Configure<KafkaConfig>(appConfig.GetSection("KafkaConfig"));
AppManager.Initialize(YLErp.Enums.SubSystemName.RealTimeCalcPosition, appConfig);
services.AddSingleton<IKafkaProduce,KafkaProduceHelper>();
services.AddHostedService<ClientPosiTask>();
services.AddHostedService<Worker>();
services.AddHostedService<BondCalcKafkTask>();
services.AddHostedService<ClientNoDMABalanceTask>();
services.AddHostedService<ClientRealBalanceTask>();
}).ConfigureLogging(logging =>
{
logging.ClearProviders();
logging.SetMinimumLevel(LogLevel.Trace);
})
.UseNLog()
.Build();
//YLServiceLocator.SetServiceProvider(host.Services);
await host.RunAsync();
}
class InnerServer
{
public string VirtualRootPath { get; private set; }
public InnerServer(string virtualRootPath)
{
VirtualRootPath = virtualRootPath.TrimToNull() ?? AppContext.BaseDirectory;
}
public string MapPath(string path)
{
if (string.IsNullOrEmpty(path))
{
return VirtualRootPath;
}
if (OperatingSystem.IsWindows())
{
path = path.TrimStart(MapPathTrim).Replace('/', '\\');
}
else
{
path = path.TrimStart(MapPathTrim).Replace('\\', '/');
}
if (path.StartsWith("App_", StringComparison.OrdinalIgnoreCase)
|| path.Equals("Scripts") || path.Equals("Style"))
{
return Path.Combine(VirtualRootPath, path);
}
return Path.Combine(VirtualRootPath, path);
}
static readonly char[] MapPathTrim = new[] { '~', '/', '\\' };
}
}
@@ -0,0 +1,59 @@
<Project Sdk="Microsoft.NET.Sdk.Worker">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<NoWarn>NU1803</NoWarn>
<RunAnalyzersDuringBuild>False</RunAnalyzersDuringBuild>
<EnableNETAnalyzers>False</EnableNETAnalyzers>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Hosting.WindowsServices" Version="6.0.1" />
<PackageReference Include="NLog.Web.AspNetCore" Version="5.1.5" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\Framework\YLErp.Core\YLErp.Core.csproj" />
<ProjectReference Include="..\..\YLErpDAL\YLErpDAL.csproj" />
</ItemGroup>
<ItemGroup>
<Content Update="appsettings.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</Content>
<Content Update="NLog.config">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</Content>
</ItemGroup>
<ItemGroup>
<None Update="appsettings.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Data\Calendars\chn.txt">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="RealTimeCalcPositionWinService.exe">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="ServiceInStallRead.txt">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="start.sh">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="stop.bat">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="stop.sh">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>
@@ -0,0 +1,64 @@
using Newtonsoft.Json;
using System.Threading;
using YLErp;
using YLErp.Abstract;
using YLErp.BLL;
using YLErp.BLL.Eod;
using YLErp.Cache;
using YLErp.Helpers;
using YLErp.Model;
using YLErp.Modules.SwapModule;
namespace RealTimeCalcPositionService
{
public class Worker : IHostedService, IDisposable
{
private readonly IYcLogger _logger;
private readonly CancellationTokenSource _cts = new CancellationTokenSource();
public Worker()
{
_logger = LogFactory.GetLogger("Worker");
}
public Task StartAsync(CancellationToken cancellationToken)
{
_logger.Info($"实时预付金计算开始:{DateTimeOffset.Now}");
Task.Run(() => ExecuteTask(_cts.Token), _cts.Token);
return Task.CompletedTask;
}
private void ExecuteTask(CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)
{
try
{
var tasks = new System.Threading.Tasks.Task[2];
tasks[0] = Task.Run(() =>
{
RealtimePnlCalc.RiskCalc();
});
tasks[1] = Task.Run(() =>
{
RealtimePnlCalc.CalcDMAMargin();
});
Task.WaitAll(tasks);
}
catch (Exception ex)
{
_logger.Error(ex, "实时预付金计算异常:" + ex.Message);
}
}
}
public async Task StopAsync(CancellationToken cancellationToken)
{
_logger.Info($"实时预付金计算停止: {DateTimeOffset.Now}");
_cts.Cancel();
await Task.CompletedTask;
}
public void Dispose()
{
_cts.Dispose();
}
}
}
@@ -0,0 +1,62 @@
{
"Logging": {
"Syslog": {
"LogLevel": {
"Default": "None"
}
},
"Journal": {
"LogLevel": {
"Default": "None"
}
},
"LogLevel": {
"Default": "Information",
"Microsoft.Hosting.Lifetime": "Warning"
}
},
"ConnectionStrings": {
"ylcms": "server=221.229.106.161;uid=roottest;pooling=true;port=20306;pwd=YieldChain!@#$2020;database=yltrs_ylcms;charset=utf8;Allow User Variables=True;SslMode=none;Connection Timeout=30;IgnoreCommandTransaction=true;",
"yladmin": "server=221.229.106.161;uid=roottest;pooling=true;port=20306;pwd=YieldChain!@#$2020;database=yltrs_admin;charset=utf8;Allow User Variables=True;SslMode=none;Connection Timeout=30;IgnoreCommandTransaction=true;",
"ylclient": "server=221.229.106.161;uid=roottest;pooling=true;port=20306;pwd=YieldChain!@#$2020;database=yltrs_client;charset=utf8;Allow User Variables=True;SslMode=none;Connection Timeout=30;IgnoreCommandTransaction=true;",
"bondoms": "server=221.229.106.161;uid=roottest;pooling=true;port=20306;pwd=YieldChain!@#$2020;database=bond_oms;charset=utf8;Allow User Variables=True;SslMode=none;Connection Timeout=30;IgnoreCommandTransaction=true;"
},
"AppSettings": {
"RunInterval": "1000",
"VirtualPathRoot": "" //兴业必须填写otc web的虚拟目录
},
"KafkaConfig": {
"BootstrapServers": "122.112.205.57:9092", // Kafka 集群的地址
"Acks": -1, // 消息确认方式,可以是 All(-1)、Leader(1)、None(0) 中的一种
"EnableIdempotence": false, // 开启幂等性,确保消息只被发送一次
"MaxInFlight": 5, // 控制生产者在同一时间最多可以发送的未确认消息数
"CompressionType": 0, // 消息压缩方式,可以是 None(0)、Gzip(1)、Snappy(2)、Lz4(3)、Zstd(4) 中的一种,
"MessageTimeoutMs": 3000, // 控制生产者等待消息确认的时间,单位是毫秒
"ClientRateTopic": "ylClientRateTopic", //客户互换费率生产topic
"HedgingAccountTopic": "ylHedgingAccountTopic", //对冲账户生产topic
"ReqAccountCapitalTopic": "ReqAccountCapital", //账户资金请求topic
"OnRspAccountCapitalTopic": "OnRspAccountCapital", //账户资金请求返回topic
"ReqInterestRateSwapInsertTopic": "ReqInterestRateSwapInsert", //收益互换交易推送请求topic
"OnRspInterestRateSwapInsertTopic": "OnRspInterestRateSwapInsert", //收益互换交易推送请求响应topic
"OnRspInterestRateSwapInsertTopicGroupId": "OnRspInterestRateSwapInsertConsumer", //收益互换交易推送请求响应消费组
"AccountCapitalTopicGroupId": "YiLian_OnRspAccountCapitalConsumer", //账户资金消费组
"ReqAssetSwapInsertTopic": "ReqAssetSwapInsert", //互换资产交易推送请求
"OnRspAssetSwapInsertTopic": "OnRspAssetSwapInsert", //互换资产交易推送请求响应
"OnRspAssetSwapInsertTopicGroupId": "OnRspAssetSwapInsertConsumer", //互换资产交易推送请求响应消费组
"ReqMarginInsertTopic": "ReqMarginInsert", //预付金交易推送请求
"OnRspMarginInsertTopic": "OnRspMarginInsert", //预付金交易推送请求响应
"OnRspMarginInsertTopicGroupId": "OnRspMarginInsertConsumer", //预付金交易推送请求响应消费组
"ReqAcctSwapTerminateTopic": "ReqAcctSwapTerminate", //平仓推送请求
"OnRspAcctSwapTerminateTopic": "OnRspAcctSwapTerminate", //平仓推送请求响应
"OnRspAcctSwapTerminateTopicGroupId": "OnRspAcctSwapTerminateConsumer", //平仓推送请求响应消费组
"ReqCalcBondTopic": "ReqCalcBond", //互换成交收益率计算器topic
"OnRspCalcBondTopic": "OnRspCalcBond", //互换成交收益率计算器消费topic
"OnRspCalcBondTopicGroupId": "OnRspCalcBondConsumer", //互换成交收益率计算器消费topic消费组
"AutoOffsetReset": 1, //Latest(0),Earliest(1),Error(2)
"EnableCalcBongd": false //是否启用kafka计算
},
"BondOmsInterface": {
"BaseUrl": "http://git.yiliantech.com:8887",
"CalculateDMAMarginUrl": "/marginAlgorithm/realTimeMarginCalc" // 多空组合预付金计算
}
}
@@ -0,0 +1,2 @@
#!/bin/bash
dotnet RealTimeCalcPositionService.dll &
@@ -0,0 +1,3 @@
#!/bin/bash
PID=$(ps -ef | grep "dotnet RealTimeCalcPositionService.dll" | grep -v grep | awk '{print $2}')
kill $PID